foreman_inventory_upload 0.0.1.dev1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +619 -0
- data/README.md +38 -0
- data/Rakefile +47 -0
- data/app/controllers/foreman_inventory_upload/react_controller.rb +7 -0
- data/app/controllers/foreman_inventory_upload/reports_controller.rb +23 -0
- data/app/controllers/foreman_inventory_upload/statuses_controller.rb +41 -0
- data/app/controllers/foreman_inventory_upload/uploads_controller.rb +31 -0
- data/app/helpers/foreman_inventory_upload_helper.rb +13 -0
- data/app/views/dashboard/_inventory_upload_widget.html.erb +2 -0
- data/app/views/foreman_inventory_upload/layouts/react.html.erb +16 -0
- data/app/views/scripts/uploader.sh.erb +31 -0
- data/config/routes.rb +10 -0
- data/lib/foreman_inventory_upload/async/generate_report_job.rb +29 -0
- data/lib/foreman_inventory_upload/async/progress_output.rb +61 -0
- data/lib/foreman_inventory_upload/async/queue_for_upload_job.rb +52 -0
- data/lib/foreman_inventory_upload/async/shell_process.rb +35 -0
- data/lib/foreman_inventory_upload/async/upload_report_job.rb +40 -0
- data/lib/foreman_inventory_upload/engine.rb +52 -0
- data/lib/foreman_inventory_upload/generators/archived_report.rb +53 -0
- data/lib/foreman_inventory_upload/generators/json_stream.rb +55 -0
- data/lib/foreman_inventory_upload/generators/metadata.rb +36 -0
- data/lib/foreman_inventory_upload/generators/queries.rb +52 -0
- data/lib/foreman_inventory_upload/generators/slice.rb +117 -0
- data/lib/foreman_inventory_upload/version.rb +3 -0
- data/lib/foreman_inventory_upload.rb +48 -0
- data/lib/tasks/foreman_inventory_upload_tasks.rake +37 -0
- data/lib/tasks/generator.rake +15 -0
- data/locale/Makefile +60 -0
- data/locale/en/foreman_yupana.po +19 -0
- data/locale/foreman_yupana.pot +19 -0
- data/locale/gemspec.rb +2 -0
- data/test/controllers/reports_controller_test.rb +21 -0
- data/test/controllers/statuses_controller_test.rb +26 -0
- data/test/controllers/uploads_controller_test.rb +21 -0
- data/test/factories/inventory_upload_factories.rb +88 -0
- data/test/test_plugin_helper.rb +26 -0
- data/test/unit/archived_report_generator_test.rb +61 -0
- data/test/unit/metadata_generator_test.rb +40 -0
- data/test/unit/shell_process_job_test.rb +27 -0
- data/test/unit/slice_generator_test.rb +60 -0
- metadata +149 -0
data/Rakefile
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
begin
|
3
|
+
require 'bundler/setup'
|
4
|
+
rescue LoadError
|
5
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
6
|
+
end
|
7
|
+
begin
|
8
|
+
require 'rdoc/task'
|
9
|
+
rescue LoadError
|
10
|
+
require 'rdoc/rdoc'
|
11
|
+
require 'rake/rdoctask'
|
12
|
+
RDoc::Task = Rake::RDocTask
|
13
|
+
end
|
14
|
+
|
15
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
16
|
+
rdoc.rdoc_dir = 'rdoc'
|
17
|
+
rdoc.title = 'ForemanInventoryUpload'
|
18
|
+
rdoc.options << '--line-numbers'
|
19
|
+
rdoc.rdoc_files.include('README.rdoc')
|
20
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
21
|
+
end
|
22
|
+
|
23
|
+
APP_RAKEFILE = File.expand_path('../test/dummy/Rakefile', __FILE__)
|
24
|
+
|
25
|
+
Bundler::GemHelper.install_tasks
|
26
|
+
|
27
|
+
require 'rake/testtask'
|
28
|
+
|
29
|
+
Rake::TestTask.new(:test) do |t|
|
30
|
+
t.libs << 'lib'
|
31
|
+
t.libs << 'test'
|
32
|
+
t.pattern = 'test/**/*_test.rb'
|
33
|
+
t.verbose = false
|
34
|
+
end
|
35
|
+
|
36
|
+
task default: :test
|
37
|
+
|
38
|
+
begin
|
39
|
+
require 'rubocop/rake_task'
|
40
|
+
RuboCop::RakeTask.new
|
41
|
+
rescue => _
|
42
|
+
puts 'Rubocop not loaded.'
|
43
|
+
end
|
44
|
+
|
45
|
+
task :default do
|
46
|
+
Rake::Task['rubocop'].execute
|
47
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module ForemanInventoryUpload
|
2
|
+
class ReportsController < ::ApplicationController
|
3
|
+
def last
|
4
|
+
label = ForemanInventoryUpload::Async::GenerateReportJob.output_label(params[:portal_user])
|
5
|
+
output = ForemanInventoryUpload::Async::ProgressOutput.get(label)&.full_output
|
6
|
+
|
7
|
+
render json: {
|
8
|
+
output: output
|
9
|
+
}, status: :ok
|
10
|
+
end
|
11
|
+
|
12
|
+
def generate
|
13
|
+
portal_user = params[:portal_user]
|
14
|
+
|
15
|
+
generated_file_name = File.join(ForemanInventoryUpload.base_folder, "#{portal_user}.tar.gz")
|
16
|
+
ForemanInventoryUpload::Async::GenerateReportJob.perform_later(generated_file_name, portal_user)
|
17
|
+
|
18
|
+
render json: {
|
19
|
+
action_status: 'success'
|
20
|
+
}, status: :ok
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module ForemanInventoryUpload
|
2
|
+
class StatusesController < ::ApplicationController
|
3
|
+
# override default "welcome screen behavior, since we don't have a model"
|
4
|
+
def welcome
|
5
|
+
true
|
6
|
+
end
|
7
|
+
|
8
|
+
def index
|
9
|
+
portal_users = RedhatAccess::TelemetryConfiguration
|
10
|
+
.where(enable_telemetry: true)
|
11
|
+
.distinct
|
12
|
+
.pluck(:portal_user)
|
13
|
+
|
14
|
+
statuses = Hash[
|
15
|
+
portal_users.map do |portal_user|
|
16
|
+
generate_report_status = status_for(portal_user, ForemanInventoryUpload::Async::GenerateReportJob)
|
17
|
+
upload_report_status = status_for(portal_user, ForemanInventoryUpload::Async::UploadReportJob)
|
18
|
+
|
19
|
+
[
|
20
|
+
portal_user,
|
21
|
+
{
|
22
|
+
generate_report_status: generate_report_status,
|
23
|
+
upload_report_status: upload_report_status
|
24
|
+
}
|
25
|
+
]
|
26
|
+
end
|
27
|
+
]
|
28
|
+
|
29
|
+
render json: {
|
30
|
+
statuses: statuses
|
31
|
+
}, status: :ok
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def status_for(portal_user, job_class)
|
37
|
+
label = job_class.output_label(portal_user)
|
38
|
+
ForemanInventoryUpload::Async::ProgressOutput.get(label)&.status
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module ForemanInventoryUpload
|
2
|
+
class UploadsController < ::ApplicationController
|
3
|
+
def last
|
4
|
+
label = ForemanInventoryUpload::Async::UploadReportJob.output_label(params[:portal_user])
|
5
|
+
output = ForemanInventoryUpload::Async::ProgressOutput.get(label)&.full_output
|
6
|
+
|
7
|
+
render json: {
|
8
|
+
output: output
|
9
|
+
}, status: :ok
|
10
|
+
end
|
11
|
+
|
12
|
+
def download_file
|
13
|
+
filename = 'hosts_report.tar.gz'
|
14
|
+
path = Rails.root.join(ForemanInventoryUpload.uploads_folder(params[:portal_user]), filename)
|
15
|
+
unless File.exist? path
|
16
|
+
return throw_flash_error(
|
17
|
+
"Path doesn't exist: #{path}"
|
18
|
+
)
|
19
|
+
end
|
20
|
+
|
21
|
+
send_file path, disposition: 'attachment', filename: filename
|
22
|
+
end
|
23
|
+
|
24
|
+
def throw_flash_error(message)
|
25
|
+
process_error(
|
26
|
+
:redirect => foreman_inventory_upload_index_path,
|
27
|
+
:error_msg => message
|
28
|
+
)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module ForemanInventoryUploadHelper
|
2
|
+
if Foreman::Version.new.minor.to_i < 23
|
3
|
+
def webpacked_plugins_css_for(*plugin_names)
|
4
|
+
css_tags_for(select_requested_plugins(plugin_names)).join.html_safe
|
5
|
+
end
|
6
|
+
|
7
|
+
def css_tags_for(requested_plugins)
|
8
|
+
requested_plugins.map do |plugin|
|
9
|
+
stylesheet_link_tag(*webpack_asset_paths(plugin.to_s, :extension => 'css'), "data-turbolinks-track" => true)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
<% content_for(:javascripts) do %>
|
2
|
+
<%= webpacked_plugins_js_for :'foreman_inventory_upload' %>
|
3
|
+
<% end %>
|
4
|
+
|
5
|
+
<% content_for(:stylesheets) do %>
|
6
|
+
<%= webpacked_plugins_css_for :'foreman_inventory_upload' %>
|
7
|
+
<% end %>
|
8
|
+
|
9
|
+
<% content_for(:content) do %>
|
10
|
+
<%= notifications %>
|
11
|
+
<div id="organization-id" data-id="<%= Organization.current.id if Organization.current %>" ></div>
|
12
|
+
<div id="user-id" data-id="<%= User.current.id if User.current %>" ></div>
|
13
|
+
<div id="ForemanInventoryUploadReactRoot"></div>
|
14
|
+
<% end %>
|
15
|
+
<%= render file: "layouts/base" %>
|
16
|
+
<%= mount_react_component('ForemanInventoryUpload', '#ForemanInventoryUploadReactRoot') %>
|
@@ -0,0 +1,31 @@
|
|
1
|
+
#! /bin/sh
|
2
|
+
|
3
|
+
DEST=<%= @upload_url %>
|
4
|
+
RH_USERNAME=<%= @rh_username %>
|
5
|
+
|
6
|
+
if [ -z "$RH_USERNAME" ]
|
7
|
+
then
|
8
|
+
IFS= read -rp "Enter username: " RH_USERNAME
|
9
|
+
fi
|
10
|
+
|
11
|
+
if [ -z "$RH_PASSWORD" ]
|
12
|
+
then
|
13
|
+
IFS= read -rsp "Enter password: " RH_PASSWORD
|
14
|
+
fi
|
15
|
+
|
16
|
+
if [ -z "$FILES" ]
|
17
|
+
then
|
18
|
+
FILES=./*.tar.gz
|
19
|
+
fi
|
20
|
+
|
21
|
+
mkdir -p done
|
22
|
+
|
23
|
+
for f in $FILES
|
24
|
+
do
|
25
|
+
curl -k -vvv -# --fail -F "file=@$f;type=application/vnd.redhat.qpc.tar+tgz" $DEST -u "$RH_USERNAME":"$RH_PASSWORD"
|
26
|
+
if [ $? -eq 0 ]; then
|
27
|
+
mv $f done/
|
28
|
+
echo "Done: $f"
|
29
|
+
fi
|
30
|
+
done
|
31
|
+
echo "Uploaded files moved to done/ folder"
|
data/config/routes.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
Rails.application.routes.draw do
|
2
|
+
namespace :foreman_inventory_upload do
|
3
|
+
get 'index', to: 'react#index'
|
4
|
+
get ':portal_user/reports/last', to: 'reports#last', constraints: { portal_user: %r{[^\/]+} }
|
5
|
+
post ':portal_user/reports', to: 'reports#generate', constraints: { portal_user: %r{[^\/]+} }
|
6
|
+
get ':portal_user/uploads/last', to: 'uploads#last', constraints: { portal_user: %r{[^\/]+} }
|
7
|
+
get ':portal_user/uploads/file', to: 'uploads#download_file', constraints: { portal_user: %r{[^\/]+} }
|
8
|
+
get 'statuses', to: 'statuses#index'
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module ForemanInventoryUpload
|
2
|
+
module Async
|
3
|
+
class GenerateReportJob < ShellProcess
|
4
|
+
def self.output_label(portal_user)
|
5
|
+
"report_for_#{portal_user}"
|
6
|
+
end
|
7
|
+
|
8
|
+
def perform(result_file, portal_user)
|
9
|
+
@result_file = result_file
|
10
|
+
@portal_user = portal_user
|
11
|
+
|
12
|
+
super(GenerateReportJob.output_label(portal_user))
|
13
|
+
|
14
|
+
QueueForUploadJob.perform_later(result_file, portal_user)
|
15
|
+
end
|
16
|
+
|
17
|
+
def command
|
18
|
+
'rake foreman_inventory_upload:report:generate'
|
19
|
+
end
|
20
|
+
|
21
|
+
def env
|
22
|
+
super.merge(
|
23
|
+
'target' => @result_file,
|
24
|
+
'portal_user' => @portal_user
|
25
|
+
)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module ForemanInventoryUpload
|
2
|
+
module Async
|
3
|
+
class ProgressOutput
|
4
|
+
def self.get(label)
|
5
|
+
ProgressOutput.new(label, :reader)
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.register(label)
|
9
|
+
ProgressOutput.new(label, :writer)
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(label, mode)
|
13
|
+
@label = label
|
14
|
+
@mode = mode
|
15
|
+
end
|
16
|
+
|
17
|
+
def buffer
|
18
|
+
@buffer ||= begin
|
19
|
+
File.open(file_name, file_mode)
|
20
|
+
rescue Errno::ENOENT
|
21
|
+
StringIO.new
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def full_output
|
26
|
+
buffer.read
|
27
|
+
end
|
28
|
+
|
29
|
+
def write_line(line)
|
30
|
+
buffer << line
|
31
|
+
buffer.fsync
|
32
|
+
end
|
33
|
+
|
34
|
+
def close
|
35
|
+
@buffer&.close
|
36
|
+
end
|
37
|
+
|
38
|
+
def status
|
39
|
+
File.read(file_name(:status))
|
40
|
+
rescue Errno::ENOENT
|
41
|
+
''
|
42
|
+
end
|
43
|
+
|
44
|
+
def status=(status)
|
45
|
+
File.atomic_write(file_name(:status)) do |status_file|
|
46
|
+
status_file.write(status)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def file_mode
|
53
|
+
@mode == :reader ? 'r' : 'w'
|
54
|
+
end
|
55
|
+
|
56
|
+
def file_name(type = 'out')
|
57
|
+
File.join(ForemanInventoryUpload.outputs_folder, "#{@label}.#{type}")
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module ForemanInventoryUpload
|
2
|
+
module Async
|
3
|
+
class QueueForUploadJob < ::ApplicationJob
|
4
|
+
def perform(report_file, portal_user)
|
5
|
+
@portal_user = portal_user
|
6
|
+
logger.debug('Ensuring objects')
|
7
|
+
ensure_ouput_folder
|
8
|
+
ensure_output_script
|
9
|
+
logger.debug("Copying #{report_file} to #{uploads_folder}")
|
10
|
+
enqueued_file_name = File.join(uploads_folder, ForemanInventoryUpload.facts_archive_name)
|
11
|
+
FileUtils.mv(report_file, enqueued_file_name)
|
12
|
+
logger.debug("Done copying #{report_file} to #{enqueued_file_name}")
|
13
|
+
|
14
|
+
UploadReportJob.perform_later(enqueued_file_name, portal_user)
|
15
|
+
end
|
16
|
+
|
17
|
+
def uploads_folder
|
18
|
+
@uploads_folder ||= ForemanInventoryUpload.uploads_folder(@portal_user)
|
19
|
+
end
|
20
|
+
|
21
|
+
def script_file
|
22
|
+
@script_file ||= File.join(uploads_folder, ForemanInventoryUpload.upload_script_file)
|
23
|
+
end
|
24
|
+
|
25
|
+
def ensure_ouput_folder
|
26
|
+
FileUtils.mkdir_p(uploads_folder)
|
27
|
+
end
|
28
|
+
|
29
|
+
def ensure_output_script
|
30
|
+
return if File.exist?(script_file)
|
31
|
+
|
32
|
+
script_source = File.join(ForemanInventoryUpload::Engine.root, 'app/views/scripts/uploader.sh.erb')
|
33
|
+
|
34
|
+
template_src = Foreman::Renderer::Source::String.new(content: File.read(script_source))
|
35
|
+
scope = Foreman::Renderer::Scope::Base.new(
|
36
|
+
source: template_src,
|
37
|
+
variables: {
|
38
|
+
upload_url: ForemanInventoryUpload.upload_url,
|
39
|
+
rh_username: @portal_user
|
40
|
+
}
|
41
|
+
)
|
42
|
+
script_source = Foreman::Renderer.render(template_src, scope)
|
43
|
+
File.write(script_file, script_source)
|
44
|
+
FileUtils.chmod('+x', script_file)
|
45
|
+
end
|
46
|
+
|
47
|
+
def logger
|
48
|
+
Foreman::Logging.logger('background')
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'open3'
|
2
|
+
|
3
|
+
module ForemanInventoryUpload
|
4
|
+
module Async
|
5
|
+
class ShellProcess < ::ApplicationJob
|
6
|
+
def perform(instance_label)
|
7
|
+
klass_name = self.class.name
|
8
|
+
logger.debug("Starting #{klass_name} with label #{instance_label}")
|
9
|
+
progress_output = ProgressOutput.register(instance_label)
|
10
|
+
Open3.popen2e(env, command) do |_stdin, stdout_stderr, wait_thread|
|
11
|
+
progress_output.status = "Running in pid #{wait_thread.pid}"
|
12
|
+
|
13
|
+
stdout_stderr.each do |out_line|
|
14
|
+
progress_output.write_line(out_line)
|
15
|
+
end
|
16
|
+
|
17
|
+
progress_output.status = wait_thread.value.to_s
|
18
|
+
end
|
19
|
+
logger.debug("Finished job #{klass_name} with label #{instance_label}")
|
20
|
+
ensure
|
21
|
+
progress_output.close
|
22
|
+
end
|
23
|
+
|
24
|
+
def command; end
|
25
|
+
|
26
|
+
def env
|
27
|
+
{}
|
28
|
+
end
|
29
|
+
|
30
|
+
def logger
|
31
|
+
Foreman::Logging.logger('background')
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module ForemanInventoryUpload
|
2
|
+
module Async
|
3
|
+
class UploadReportJob < ShellProcess
|
4
|
+
def self.output_label(portal_user)
|
5
|
+
"upload_for_#{portal_user}"
|
6
|
+
end
|
7
|
+
|
8
|
+
def perform(filename, portal_user)
|
9
|
+
@portal_user = portal_user
|
10
|
+
@filename = filename
|
11
|
+
|
12
|
+
super(UploadReportJob.output_label(portal_user))
|
13
|
+
end
|
14
|
+
|
15
|
+
def command
|
16
|
+
File.join(File.dirname(@filename), ForemanInventoryUpload.upload_script_file)
|
17
|
+
end
|
18
|
+
|
19
|
+
def env
|
20
|
+
super.merge(
|
21
|
+
'RH_USERNAME' => rh_username,
|
22
|
+
'RH_PASSWORD' => rh_password,
|
23
|
+
'FILES' => @filename
|
24
|
+
)
|
25
|
+
end
|
26
|
+
|
27
|
+
def rh_credentials
|
28
|
+
@rh_credentials ||= RedhatAccess::TelemetryConfiguration.where(portal_user: @portal_user).last
|
29
|
+
end
|
30
|
+
|
31
|
+
def rh_username
|
32
|
+
@portal_user
|
33
|
+
end
|
34
|
+
|
35
|
+
def rh_password
|
36
|
+
rh_credentials.portal_password
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'katello'
|
2
|
+
require 'redhat_access'
|
3
|
+
|
4
|
+
module ForemanInventoryUpload
|
5
|
+
class Engine < ::Rails::Engine
|
6
|
+
engine_name 'foreman_inventory_upload'
|
7
|
+
|
8
|
+
config.autoload_paths += Dir["#{config.root}/app/controllers/concerns"]
|
9
|
+
config.autoload_paths += Dir["#{config.root}/app/helpers/concerns"]
|
10
|
+
config.autoload_paths += Dir["#{config.root}/app/models/concerns"]
|
11
|
+
config.autoload_paths += Dir["#{config.root}/app/overrides"]
|
12
|
+
config.autoload_paths += Dir["#{config.root}/lib"]
|
13
|
+
|
14
|
+
# Add any db migrations
|
15
|
+
initializer 'foreman_inventory_upload.load_app_instance_data' do |app|
|
16
|
+
ForemanInventoryUpload::Engine.paths['db/migrate'].existent.each do |path|
|
17
|
+
app.config.paths['db/migrate'] << path
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
initializer 'foreman_inventory_upload.register_plugin', :before => :finisher_hook do |_app|
|
22
|
+
Foreman::Plugin.register :foreman_inventory_upload do
|
23
|
+
requires_foreman '>= 1.20'
|
24
|
+
|
25
|
+
# Add permissions
|
26
|
+
security_block :foreman_inventory_upload do
|
27
|
+
permission :view_foreman_inventory_upload, :'foreman_inventory_upload/reports' => [:last]
|
28
|
+
end
|
29
|
+
|
30
|
+
# Add a new role called 'Discovery' if it doesn't exist
|
31
|
+
role 'ForemanInventoryUpload', [:view_foreman_inventory_upload]
|
32
|
+
|
33
|
+
# Adding a sub menu after hosts menu
|
34
|
+
sub_menu :top_menu, :foreman_inventory_upload, :caption => N_('RH Inventory'), :icon => 'fa fa-cloud-upload' do
|
35
|
+
menu :top_menu, :level1, :caption => N_('Manage'), :url_hash => { controller: :'foreman_inventory_upload/react', :action=>:index}
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
rake_tasks do
|
41
|
+
Rake::Task['db:seed'].enhance do
|
42
|
+
ForemanInventoryUpload::Engine.load_seed
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
initializer 'foreman_inventory_upload.register_gettext', after: :load_config_initializers do |_app|
|
47
|
+
locale_dir = File.join(File.expand_path('../..', __dir__), 'locale')
|
48
|
+
locale_domain = 'foreman_inventory_upload'
|
49
|
+
Foreman::Gettext::Support.add_text_domain locale_domain, locale_dir
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module ForemanInventoryUpload
|
2
|
+
module Generators
|
3
|
+
class ArchivedReport
|
4
|
+
def initialize(target, logger = Rails.logger)
|
5
|
+
@target = target
|
6
|
+
@logger = logger
|
7
|
+
end
|
8
|
+
|
9
|
+
def render(portal_user)
|
10
|
+
Dir.mktmpdir do |tmpdir|
|
11
|
+
@logger.info "Started generating hosts report in #{tmpdir}"
|
12
|
+
host_batches = ForemanInventoryUpload::Generators::Queries.for_report(portal_user)
|
13
|
+
File.open(File.join(tmpdir, 'metadata.json'), 'w') do |metadata_out|
|
14
|
+
metadata_generator = ForemanInventoryUpload::Generators::Metadata.new(metadata_out)
|
15
|
+
metadata_generator.render do |inner_generator|
|
16
|
+
first = true
|
17
|
+
host_batches.each do |hosts_batch|
|
18
|
+
slice_id = Foreman.uuid
|
19
|
+
hosts_count = hosts_batch.count
|
20
|
+
@logger.info "Adding slice #{slice_id} with #{hosts_count} hosts"
|
21
|
+
generate_slice(tmpdir, slice_id, hosts_batch)
|
22
|
+
inner_generator.add_slice(slice_id, hosts_count, first)
|
23
|
+
first = false
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
@logger.info 'Report generation finished'
|
28
|
+
|
29
|
+
@logger.info 'Archiving generated report'
|
30
|
+
# success = system('tar', '-zcvf', @target, '-C', tmpdir, '.')
|
31
|
+
Open3.popen2e('tar', '-zcvf', @target, '-C', tmpdir, '.') do |_in, out, wait_thr|
|
32
|
+
@logger.info("tar: #{out.read}")
|
33
|
+
|
34
|
+
if wait_thr.value.success?
|
35
|
+
@logger.info 'Report archived successfully'
|
36
|
+
else
|
37
|
+
@logger.info "Tar command failed: #{$CHILD_STATUS}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def generate_slice(tmpdir, slice_id, hosts_batch)
|
46
|
+
File.open(File.join(tmpdir, "#{slice_id}.json"), 'w') do |slice_out|
|
47
|
+
slice_generator = ForemanInventoryUpload::Generators::Slice.new(hosts_batch, slice_out, slice_id)
|
48
|
+
slice_generator.render
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module ForemanInventoryUpload
|
2
|
+
module Generators
|
3
|
+
class JsonStream
|
4
|
+
attr_reader :out
|
5
|
+
def initialize(out)
|
6
|
+
@out = out
|
7
|
+
end
|
8
|
+
|
9
|
+
def array
|
10
|
+
@out << '['
|
11
|
+
yield
|
12
|
+
@out << ']'
|
13
|
+
end
|
14
|
+
|
15
|
+
def object
|
16
|
+
@out << '{'
|
17
|
+
yield
|
18
|
+
@out << '}'
|
19
|
+
end
|
20
|
+
|
21
|
+
def comma
|
22
|
+
@out << ', '
|
23
|
+
end
|
24
|
+
|
25
|
+
def raw(string)
|
26
|
+
@out << string
|
27
|
+
end
|
28
|
+
|
29
|
+
def simple_field(name, value, last = false)
|
30
|
+
@out << "\"#{name}\": #{stringify_value(value)}#{last ? '' : ','}" unless value.nil?
|
31
|
+
end
|
32
|
+
|
33
|
+
def array_field(name, last = false, &block)
|
34
|
+
@out << "\"#{name}\": "
|
35
|
+
array(&block)
|
36
|
+
@out << ',' unless last
|
37
|
+
end
|
38
|
+
|
39
|
+
def object_field(name, last = false, &block)
|
40
|
+
@out << "\"#{name}\": "
|
41
|
+
object(&block)
|
42
|
+
@out << ',' unless last
|
43
|
+
end
|
44
|
+
|
45
|
+
def stringify_value(value)
|
46
|
+
return value if value.is_a?(Integer)
|
47
|
+
return value if value.is_a?(TrueClass)
|
48
|
+
return value if value.is_a?(FalseClass)
|
49
|
+
return value.to_json if value.is_a?(Hash)
|
50
|
+
|
51
|
+
"\"#{value}\""
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module ForemanInventoryUpload
|
2
|
+
module Generators
|
3
|
+
class Metadata
|
4
|
+
def initialize(output = [])
|
5
|
+
@stream = JsonStream.new(output)
|
6
|
+
end
|
7
|
+
|
8
|
+
def add_slice(slice_id, hosts_count, first)
|
9
|
+
@stream.comma unless first
|
10
|
+
|
11
|
+
@stream.object_field(slice_id, :last) do
|
12
|
+
@stream.simple_field('number_hosts', hosts_count, :last)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def render(metadata = nil, &block)
|
17
|
+
render_report(metadata, &block)
|
18
|
+
@stream.out
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def render_report(metadata)
|
24
|
+
@stream.object do
|
25
|
+
@stream.simple_field('report_id', Foreman.uuid)
|
26
|
+
@stream.simple_field('host_inventory_api_version', '1.0')
|
27
|
+
@stream.simple_field('source', 'Satellite')
|
28
|
+
@stream.simple_field('source_metadata', metadata)
|
29
|
+
@stream.object_field('report_slices', :last) do
|
30
|
+
yield(self)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|