hammer_cli_katello 0.0.24 → 0.0.25
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/hammer_cli_katello.rb +1 -0
- data/lib/hammer_cli_katello/activation_key.rb +8 -6
- data/lib/hammer_cli_katello/capsule.rb +2 -21
- data/lib/hammer_cli_katello/commands.rb +2 -2
- data/lib/hammer_cli_katello/content_host.rb +3 -49
- data/lib/hammer_cli_katello/content_view.rb +19 -4
- data/lib/hammer_cli_katello/content_view_puppet_module.rb +8 -0
- data/lib/hammer_cli_katello/content_view_version.rb +69 -20
- data/lib/hammer_cli_katello/host.rb +4 -0
- data/lib/hammer_cli_katello/host_collection.rb +3 -22
- data/lib/hammer_cli_katello/host_errata.rb +1 -1
- data/lib/hammer_cli_katello/host_subscription.rb +31 -0
- data/lib/hammer_cli_katello/id_resolver.rb +45 -65
- data/lib/hammer_cli_katello/katello_environment_name_resolvable.rb +33 -0
- data/lib/hammer_cli_katello/lifecycle_environment_name_resolvable.rb +1 -13
- data/lib/hammer_cli_katello/ping.rb +4 -0
- data/lib/hammer_cli_katello/repository.rb +10 -8
- data/lib/hammer_cli_katello/search_options_creators.rb +70 -0
- data/lib/hammer_cli_katello/version.rb +1 -1
- data/test/data/3.0/foreman_api.json +1 -0
- data/test/functional/activaton_key/list_test.rb +69 -0
- data/test/functional/content_view/content_view_helpers.rb +10 -0
- data/test/functional/content_view/create_test.rb +119 -0
- data/test/functional/content_view/list_test.rb +67 -0
- data/test/functional/content_view/version/incremental_update_test.rb +91 -0
- data/test/functional/host/errata/apply_test.rb +46 -0
- data/test/functional/host/host_helpers.rb +10 -0
- data/test/functional/host/subscription/register_test.rb +53 -0
- data/test/functional/host/subscription/unregister_test.rb +37 -0
- data/test/functional/lifecycle_environment/lifecycle_environment_helpers.rb +17 -0
- data/test/functional/organization/organization_helpers.rb +10 -0
- data/test/functional/ping_test.rb +19 -0
- data/test/functional/product/product_helpers.rb +8 -0
- data/test/functional/repository/info_test.rb +46 -0
- data/test/functional/repository/list_test.rb +69 -0
- data/test/functional/repository/repository_helpers.rb +9 -0
- data/test/functional/repository/synchronize_test.rb +57 -0
- data/test/functional/repository/upload_test.rb +86 -0
- data/test/task_helper.rb +7 -0
- data/test/test_helper.rb +16 -3
- data/test/unit/id_resolver_test.rb +32 -0
- data/test/unit/search_options_creators_test.rb +107 -0
- metadata +53 -3
@@ -0,0 +1,10 @@
|
|
1
|
+
module OrganizationHelpers
|
2
|
+
|
3
|
+
def expect_organization_search(name, id)
|
4
|
+
ex = api_expects(:organizations, :index, 'Find the organization') do |par|
|
5
|
+
par[:search] == "name = \"#{name}\""
|
6
|
+
end
|
7
|
+
ex.at_least_once.returns(index_response([{'id' => id}]))
|
8
|
+
end
|
9
|
+
|
10
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
|
3
|
+
describe 'ping' do
|
4
|
+
it 'does not require authentication' do
|
5
|
+
api_expects(:ping, :index).returns(
|
6
|
+
'status' => 'ok',
|
7
|
+
'services' => {
|
8
|
+
'foreman_tasks' => {'status' => 'ok', 'duration_ms' => '34'},
|
9
|
+
'foreman_auth' => {'status' => 'ok', 'duration_ms' => '34'},
|
10
|
+
'candlepin' => {'status' => 'ok', 'duration_ms' => '34'},
|
11
|
+
'candlepin_auth' => {'status' => 'ok', 'duration_ms' => '34'},
|
12
|
+
'pulp' => {'status' => 'ok', 'duration_ms' => '34'},
|
13
|
+
'pulp_auth' => {'status' => 'ok', 'duration_ms' => '34'}
|
14
|
+
}
|
15
|
+
)
|
16
|
+
|
17
|
+
run_cmd(%w(ping))
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '../test_helper')
|
2
|
+
require File.join(File.dirname(__FILE__), '../product/product_helpers')
|
3
|
+
require File.join(File.dirname(__FILE__), './repository_helpers')
|
4
|
+
|
5
|
+
describe "get repository info" do
|
6
|
+
include ProductHelpers
|
7
|
+
include RepositoryHelpers
|
8
|
+
|
9
|
+
before do
|
10
|
+
@cmd = %w(repository info)
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:org_id) { 1 }
|
14
|
+
let(:product_id) { 2 }
|
15
|
+
let(:repo_id) { 3 }
|
16
|
+
|
17
|
+
it "Shows information about a repository" do
|
18
|
+
params = ["--id=#{repo_id}"]
|
19
|
+
|
20
|
+
ex = api_expects(:repositories, :show, "Get info") do |par|
|
21
|
+
par["id"] == repo_id.to_s
|
22
|
+
end
|
23
|
+
|
24
|
+
ex.returns({})
|
25
|
+
|
26
|
+
result = run_cmd(@cmd + params)
|
27
|
+
assert(result.exit_code, 0)
|
28
|
+
end
|
29
|
+
|
30
|
+
it "Shows information about a repository with organization-id and product name" do
|
31
|
+
params = ["--name=test_repo", "--product=test_product", "--organization-id=#{org_id}"]
|
32
|
+
|
33
|
+
expect_product_search(org_id, 'test_product', product_id)
|
34
|
+
|
35
|
+
expect_repository_search(org_id, product_id, 'test_repo', repo_id)
|
36
|
+
|
37
|
+
ex2 = api_expects(:repositories, :show, "Get info") do |par|
|
38
|
+
par["id"] == repo_id
|
39
|
+
end
|
40
|
+
|
41
|
+
ex2.returns({})
|
42
|
+
|
43
|
+
result = run_cmd(@cmd + params)
|
44
|
+
assert(result.exit_code, 0)
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '../test_helper')
|
2
|
+
require File.join(File.dirname(__FILE__), '../lifecycle_environment/lifecycle_environment_helpers')
|
3
|
+
|
4
|
+
require 'hammer_cli_katello/content_view_puppet_module'
|
5
|
+
|
6
|
+
describe 'listing repositories' do
|
7
|
+
include LifecycleEnvironmentHelpers
|
8
|
+
|
9
|
+
before do
|
10
|
+
@cmd = %w(repository list)
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:org_id) { 1 }
|
14
|
+
let(:lifecycle_env_id) { 1 }
|
15
|
+
let(:empty_response) do {
|
16
|
+
"total" => 0,
|
17
|
+
"subtotal" => 0,
|
18
|
+
"page" => "1",
|
19
|
+
"per_page" => "1000",
|
20
|
+
"error" => nil,
|
21
|
+
"search" => nil,
|
22
|
+
"sort" => {
|
23
|
+
"by" => nil,
|
24
|
+
"order" => nil
|
25
|
+
},
|
26
|
+
"results" => []
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
it "lists an organizations repositories" do
|
31
|
+
params = ["--organization-id=#{org_id}"]
|
32
|
+
|
33
|
+
ex = api_expects(:repositories, :index, 'Organizations repositories list') do |par|
|
34
|
+
par['organization_id'] == org_id && par['page'] == 1 &&
|
35
|
+
par['per_page'] == 1000
|
36
|
+
end
|
37
|
+
|
38
|
+
ex.returns(empty_response)
|
39
|
+
|
40
|
+
expected_result = success_result("---|------|---------|--------------|----
|
41
|
+
ID | NAME | PRODUCT | CONTENT TYPE | URL
|
42
|
+
---|------|---------|--------------|----
|
43
|
+
")
|
44
|
+
|
45
|
+
result = run_cmd(@cmd + params)
|
46
|
+
assert_cmd(expected_result, result)
|
47
|
+
end
|
48
|
+
|
49
|
+
it "lists the repositories belonging to a lifecycle-environment by name" do
|
50
|
+
params = ['--organization-id=1', '--environment=test']
|
51
|
+
|
52
|
+
expect_lifecycle_environment_search(org_id, 'test', lifecycle_env_id)
|
53
|
+
|
54
|
+
ex = api_expects(:repositories, :index, 'lifecycle repositories list') do |par|
|
55
|
+
par['organization_id'] == org_id && par['page'] == 1 &&
|
56
|
+
par['per_page'] == 1000
|
57
|
+
end
|
58
|
+
|
59
|
+
ex.returns(empty_response)
|
60
|
+
|
61
|
+
expected_result = success_result("---|------|---------|--------------|----
|
62
|
+
ID | NAME | PRODUCT | CONTENT TYPE | URL
|
63
|
+
---|------|---------|--------------|----
|
64
|
+
")
|
65
|
+
|
66
|
+
result = run_cmd(@cmd + params)
|
67
|
+
assert_cmd(expected_result, result)
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
module RepositoryHelpers
|
2
|
+
def expect_repository_search(org_id, product_id, name, id)
|
3
|
+
ex = api_expects(:repositories, :index, 'Find a repository') do |par|
|
4
|
+
par['name'] == name && par['organization_id'] == org_id &&
|
5
|
+
par['product_id'] == product_id
|
6
|
+
end
|
7
|
+
ex.returns(index_response([{'id' => id}]))
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '../test_helper')
|
2
|
+
require File.join(File.dirname(__FILE__), '../product/product_helpers')
|
3
|
+
require File.join(File.dirname(__FILE__), './repository_helpers')
|
4
|
+
|
5
|
+
describe 'Synchronize a repository' do
|
6
|
+
include ForemanTaskHelpers
|
7
|
+
include ProductHelpers
|
8
|
+
include RepositoryHelpers
|
9
|
+
|
10
|
+
before do
|
11
|
+
@cmd = %w(repository synchronize)
|
12
|
+
end
|
13
|
+
|
14
|
+
let(:org_id) { 1 }
|
15
|
+
let(:repo_id) { 2 }
|
16
|
+
let(:product_id) { 3 }
|
17
|
+
let(:sync_response) do
|
18
|
+
{
|
19
|
+
'id' => repo_id,
|
20
|
+
'state' => 'planned'
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
it "synchronizes a repository" do
|
25
|
+
params = ["--id=#{repo_id}"]
|
26
|
+
|
27
|
+
ex = api_expects(:repositories, :sync, 'Repository is synced') do |par|
|
28
|
+
par['id'] == repo_id.to_s
|
29
|
+
end
|
30
|
+
|
31
|
+
ex.returns(sync_response)
|
32
|
+
|
33
|
+
expect_foreman_task('3')
|
34
|
+
|
35
|
+
result = run_cmd(@cmd + params)
|
36
|
+
assert(result.exit_code, 0)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "synchronizes a repository with a repository name" do
|
40
|
+
params = ["--name=test_repo", "--product=test_product", "--organization-id=#{org_id}"]
|
41
|
+
|
42
|
+
expect_product_search(org_id, "test_product", product_id)
|
43
|
+
|
44
|
+
expect_repository_search(org_id, product_id, "test_repo", repo_id)
|
45
|
+
|
46
|
+
ex = api_expects(:repositories, :sync, 'Repository is synced') do |par|
|
47
|
+
par['id'] == repo_id
|
48
|
+
end
|
49
|
+
|
50
|
+
ex.returns(sync_response)
|
51
|
+
|
52
|
+
expect_foreman_task('3')
|
53
|
+
|
54
|
+
result = run_cmd(@cmd + params)
|
55
|
+
assert(result.exit_code, 0)
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '../test_helper')
|
2
|
+
require File.join(File.dirname(__FILE__), '../product/product_helpers')
|
3
|
+
require File.join(File.dirname(__FILE__), './repository_helpers')
|
4
|
+
|
5
|
+
describe 'upload repository' do
|
6
|
+
include ProductHelpers
|
7
|
+
include RepositoryHelpers
|
8
|
+
|
9
|
+
before do
|
10
|
+
@cmd = %w(repository upload-content)
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:org_id) { 1 }
|
14
|
+
let(:product_id) { 2 }
|
15
|
+
let(:repo_id) { 3 }
|
16
|
+
let(:path) { "./test.rpm" }
|
17
|
+
let(:upload_id) { "1234" }
|
18
|
+
let(:_href) { "/pulp/api/v2/content/uploads/#{upload_id}" }
|
19
|
+
let(:upload_response) do
|
20
|
+
{
|
21
|
+
"upload_id" => upload_id,
|
22
|
+
"_href" => _href
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
it "uploads a package" do
|
27
|
+
File.new("test.rpm", "w")
|
28
|
+
|
29
|
+
params = ["--id=#{repo_id}", "--path=#{path}"]
|
30
|
+
|
31
|
+
ex = api_expects(:content_uploads, :create, "Create upload for content") do |par|
|
32
|
+
par[:repository_id] == repo_id.to_s
|
33
|
+
end
|
34
|
+
|
35
|
+
ex.returns(upload_response)
|
36
|
+
|
37
|
+
ex2 = api_expects(:repositories, :import_uploads, 'Take in an upload') do |par|
|
38
|
+
par[:id] == repo_id.to_s && par[:upload_ids] == ['1234']
|
39
|
+
end
|
40
|
+
|
41
|
+
ex2.returns("")
|
42
|
+
|
43
|
+
ex3 = api_expects(:content_uploads, :destroy, "Delete the upload") do |par|
|
44
|
+
par[:id] == upload_id && par[:repository_id] == repo_id.to_s
|
45
|
+
end
|
46
|
+
|
47
|
+
ex3.returns("")
|
48
|
+
|
49
|
+
result = run_cmd(@cmd + params)
|
50
|
+
assert(result.exit_code, 0)
|
51
|
+
File.delete("test.rpm")
|
52
|
+
end
|
53
|
+
|
54
|
+
it "uploads a package with an organization-id" do
|
55
|
+
File.new("test.rpm", "w")
|
56
|
+
|
57
|
+
params = ["--name=test_repo", "--product=test_product", "--organization-id=#{org_id}",
|
58
|
+
"--path=#{path}"]
|
59
|
+
|
60
|
+
expect_product_search(org_id, 'test_product', product_id)
|
61
|
+
|
62
|
+
expect_repository_search(org_id, product_id, 'test_repo', repo_id)
|
63
|
+
|
64
|
+
ex = api_expects(:content_uploads, :create, "Create upload for content") do |par|
|
65
|
+
par[:repository_id] == repo_id
|
66
|
+
end
|
67
|
+
|
68
|
+
ex.returns(upload_response)
|
69
|
+
|
70
|
+
ex2 = api_expects(:repositories, :import_uploads, 'Take in an upload') do |par|
|
71
|
+
par[:id] == repo_id && par[:upload_ids] == ['1234']
|
72
|
+
end
|
73
|
+
|
74
|
+
ex2.returns("")
|
75
|
+
|
76
|
+
ex3 = api_expects(:content_uploads, :destroy, "Delete the upload") do |par|
|
77
|
+
par[:id] == upload_id && par[:repository_id] == repo_id
|
78
|
+
end
|
79
|
+
|
80
|
+
ex3.returns("")
|
81
|
+
|
82
|
+
result = run_cmd(@cmd + params)
|
83
|
+
assert(result.exit_code, 0)
|
84
|
+
File.delete("test.rpm")
|
85
|
+
end
|
86
|
+
end
|
data/test/task_helper.rb
ADDED
data/test/test_helper.rb
CHANGED
@@ -1,11 +1,24 @@
|
|
1
|
+
if RUBY_VERSION > "2.2"
|
2
|
+
# Coverage - Keep these two lines at the top of this file
|
3
|
+
require 'simplecov'
|
4
|
+
require 'coveralls'
|
5
|
+
SimpleCov.formatters = [SimpleCov::Formatter::HTMLFormatter, Coveralls::SimpleCov::Formatter]
|
6
|
+
SimpleCov.start do
|
7
|
+
minimum_coverage 46
|
8
|
+
refuse_coverage_drop
|
9
|
+
track_files "lib/**/*.rb"
|
10
|
+
add_filter '/test/'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
require File.join(File.dirname(__FILE__), './task_helper.rb')
|
1
15
|
require 'minitest/autorun'
|
2
16
|
require 'minitest/spec'
|
3
|
-
require
|
4
|
-
|
17
|
+
require 'mocha/setup'
|
5
18
|
require 'hammer_cli'
|
6
19
|
require 'hammer_cli_foreman/commands'
|
7
20
|
|
8
|
-
KATELLO_VERSION = Gem::Version.new(ENV['TEST_API_VERSION'] || '
|
21
|
+
KATELLO_VERSION = Gem::Version.new(ENV['TEST_API_VERSION'] || '3.0')
|
9
22
|
|
10
23
|
HammerCLIForeman.stubs(:resource_config).returns(
|
11
24
|
:apidoc_cache_dir => 'test/data/' + KATELLO_VERSION.to_s,
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require_relative '../test_helper'
|
2
|
+
require 'hammer_cli_katello/id_resolver'
|
3
|
+
|
4
|
+
module HammerCLIKatello
|
5
|
+
describe IdResolver do
|
6
|
+
let(:api) { mock('api') }
|
7
|
+
let(:searchables) { mock('searchables') }
|
8
|
+
let(:id_resolver) { IdResolver.new api, searchables }
|
9
|
+
describe '#repository_ids' do
|
10
|
+
before(:each) do
|
11
|
+
api.stubs(:resources).returns([])
|
12
|
+
end
|
13
|
+
it 'accepts repository_ids' do
|
14
|
+
id_resolver.repository_ids(
|
15
|
+
'option_repository_ids' => [1, 2]
|
16
|
+
).must_equal [1, 2]
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'accepts repository_names' do
|
20
|
+
id_resolver.stubs(:find_resources).returns(
|
21
|
+
[
|
22
|
+
{'id' => 1, 'name' => 'repo1'},
|
23
|
+
{'id' => 2, 'name' => 'repo2'}
|
24
|
+
]
|
25
|
+
)
|
26
|
+
id_resolver.repository_ids(
|
27
|
+
'option_names' => %w(repo1 repo2)
|
28
|
+
).must_equal [1, 2]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
require_relative '../test_helper'
|
2
|
+
require 'hammer_cli_katello/search_options_creators'
|
3
|
+
|
4
|
+
class SearchOptionsCreatorsMock
|
5
|
+
include HammerCLIKatello::SearchOptionsCreators
|
6
|
+
|
7
|
+
def one
|
8
|
+
end
|
9
|
+
|
10
|
+
def two
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe HammerCLIKatello::SearchOptionsCreators do
|
15
|
+
|
16
|
+
let(:search_options_creators) { SearchOptionsCreatorsMock.new }
|
17
|
+
let(:options) { Hash.new }
|
18
|
+
let(:resource) { mock('ApipieBindings::Resource') }
|
19
|
+
|
20
|
+
describe '#create_repositories_search_options' do
|
21
|
+
it 'handles an array of names' do
|
22
|
+
search_options_creators.create_repositories_search_options(
|
23
|
+
'option_names' => ['repo1']
|
24
|
+
)['names'].must_equal ['repo1']
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'handles a single value name' do
|
28
|
+
search_options_creators.create_repositories_search_options(
|
29
|
+
'option_name' => 'repo1'
|
30
|
+
)['name'].must_equal 'repo1'
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'handles a single value product_id' do
|
34
|
+
search_options_creators.create_repositories_search_options(
|
35
|
+
'option_product_id' => 3
|
36
|
+
)['product_id'].must_equal 3
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe '#create_content_view_versions_search_options(options)' do
|
41
|
+
it 'handles a single value environment_id' do
|
42
|
+
search_options_creators.create_content_view_versions_search_options(
|
43
|
+
'option_environment_id' => 3,
|
44
|
+
'option_content_view_id' => :required_option
|
45
|
+
)['environment_id'].must_equal 3
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'handles a single value content_view_id' do
|
49
|
+
search_options_creators.create_content_view_versions_search_options(
|
50
|
+
'option_content_view_id' => 3
|
51
|
+
)['content_view_id'].must_equal 3
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'handles a single value version' do
|
55
|
+
search_options_creators.create_content_view_versions_search_options(
|
56
|
+
'option_version' => 3
|
57
|
+
)['version'].must_equal 3
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe 'without the katello api' do
|
62
|
+
let(:api) { mock('api') }
|
63
|
+
|
64
|
+
before(:each) do
|
65
|
+
search_options_creators.expects(:create_search_options_without_katello_api)
|
66
|
+
search_options_creators.stubs(:api).returns(api)
|
67
|
+
api.stubs(:resource)
|
68
|
+
end
|
69
|
+
|
70
|
+
describe '#create_organizations_search_options(options)' do
|
71
|
+
it 'does not use the katello api' do
|
72
|
+
search_options_creators.create_organizations_search_options(:anything)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe '#create_smart_proxies_search_options(options)' do
|
77
|
+
it 'does not use the katello api' do
|
78
|
+
search_options_creators.create_organizations_search_options(:anything)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe '#create_capsules_search_options(options)' do
|
83
|
+
it 'does not use the katello api' do
|
84
|
+
search_options_creators.create_organizations_search_options(:anything)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe '#create_search_options_with_katello_api(options, resource)' do
|
89
|
+
it 'does not use the katello api' do
|
90
|
+
search_options_creators.create_organizations_search_options(:anything)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
end # describe 'without the katello api'
|
95
|
+
|
96
|
+
describe '#create_search_options_with_katello_api' do
|
97
|
+
it 'translates all searchable fields from options' do
|
98
|
+
search_options_creators.stubs(:searchables).
|
99
|
+
returns([search_options_creators.method(:one), search_options_creators.method(:two)])
|
100
|
+
|
101
|
+
search_options_creators.create_search_options_with_katello_api(
|
102
|
+
{'option_one' => 1, 'option_two' => 2}, resource
|
103
|
+
).must_equal('one' => '1', 'two' => '2')
|
104
|
+
end
|
105
|
+
end # describe '#create_search_options_with_katello_api'
|
106
|
+
|
107
|
+
end # describe HammerCLIKatello::SearchOptionsCreators
|