Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CP] Katello 4.14 RC3 version bump and cp #11138

Merged
merged 6 commits into from
Sep 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/assets/javascripts/katello/common/katello.common.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ KT.common = (function() {
}
},
spinner_path : function() {
return "/assets/spinner.gif";
return document.querySelector('#sync_toggle_cont').dataset.spinnerAssetPath;
},
to_human_readable_bytes : function(bytes) {
var sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,7 @@ $("#sync_product_form")
});

$("#sync_toggle").change(function () {
var img = "<img src='" + KT.common.spinner_path() + "'>";
var img = "<img src='" + KT.common.spinner_path() + "'>";
$("#sync_toggle_cont").append(img);
if ($(this).is(":checked")) {
KT.content.showOnlySyncing();
Expand Down
4 changes: 2 additions & 2 deletions app/controllers/katello/api/v2/api_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,8 @@ def scoped_search(query, default_sort_by, default_sort_order, options = {})
else
query = query.paginate(paginate_options)
end
page = params[:page] || 1
per_page = params[:per_page] || Setting[:entries_per_page]
page = metadata_page # from Foreman Api::V2::BaseController
per_page = metadata_per_page
query = (total.zero? || subtotal.zero?) ? blank_query : query

if options[:csv]
Expand Down
17 changes: 16 additions & 1 deletion app/controllers/katello/api/v2/host_packages_controller.rb
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
module Katello
class Api::V2::HostPackagesController < Api::V2::ApiController
include Katello::Concerns::FilteredAutoCompleteSearch
include Katello::Concerns::Api::V2::RepositoryContentController

UPGRADABLE = "upgradable".freeze
UP_TO_DATE = "up-to-date".freeze
VERSION_STATUSES = [UPGRADABLE, UP_TO_DATE].freeze

before_action :require_packages_or_groups, :only => [:install, :remove]
before_action :require_packages_only, :only => [:upgrade]
before_action :find_editable_host_with_facet, :except => :index
before_action :find_editable_host_with_facet, :except => [:index, :installed_packages]
before_action :find_host, :only => :index

resource_description do
Expand All @@ -21,6 +22,20 @@ class Api::V2::HostPackagesController < Api::V2::ApiController
param :groups, Array, :desc => N_("List of package group names (Deprecated)"), :required => false
end

api :GET, "/host_packages/installed_packages", N_("Return a list of installed packages distinct by name")
param_group :search, ::Katello::Api::V2::ApiController
def installed_packages
_sort_by, _sort_order, options = sort_options
sort_by = 'name'
sort_order = 'asc'

options[:select] = "DISTINCT ON (#{::Katello::InstalledPackage.table_name}.name) #{::Katello::InstalledPackage.table_name}.id, #{::Katello::InstalledPackage.table_name}.name"
final_relation = ::Katello::InstalledPackage.all

result = scoped_search(final_relation, sort_by, sort_order, options)
respond_for_index(:collection => result, :template => "installed_packages")
end

api :GET, "/hosts/:host_id/packages", N_("List packages installed on the host")
param :host_id, :number, :required => true, :desc => N_("ID of the host")
param :include_latest_upgradable, :boolean, :desc => N_("Also include the latest upgradable package version for each host package")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class Api::V2::RepositoriesBulkActionsController < Api::V2::ApiController
param :ids, Array, :desc => N_("List of repository ids"), :required => true
def destroy_repositories
deletion_authorized_repositories = @repositories.deletable
unpromoted_repos = Setting.find_by(name: 'delete_repo_across_cv')&.value ? deletion_authorized_repositories : deletion_authorized_repositories.reject { |repo| repo.promoted? && repo.content_views.generated_for_none.exists? }
unpromoted_repos = Setting[:delete_repo_across_cv] ? deletion_authorized_repositories : deletion_authorized_repositories.reject { |repo| repo.promoted? && repo.content_views.generated_for_none.exists? }
unpromoted_repos_non_last_affected_repo = unpromoted_repos.reject { |repo| repo.filters.any? { |filter| filter.repositories.size == 1 } }
messages1 = format_bulk_action_messages(
:success => "",
Expand Down Expand Up @@ -36,7 +36,7 @@ def destroy_repositories
task = async_task(::Actions::BulkAction,
::Actions::Katello::Repository::Destroy,
unpromoted_repos_non_last_affected_repo,
remove_from_content_view_versions: Setting.find_by(name: 'delete_repo_across_cv')&.value
remove_from_content_view_versions: Setting[:delete_repo_across_cv]
)
else
status = 400
Expand Down
2 changes: 1 addition & 1 deletion app/models/katello/concerns/host_managed_extensions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,7 @@ def rhel_eos_schedule_index
end

def package_names_for_job_template(action:, search:, versions: nil)
if self.operatingsystem.family == 'Debian'
if self&.operatingsystem&.family == 'Debian'
deb_names_for_job_template(action: action, search: search)
else
yum_names_for_job_template(action: action, search: search, versions: versions)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
object false

extends "katello/api/v2/common/metadata"
child @collection[:results] => :results do |_results|
attributes :name, :id
end
2 changes: 1 addition & 1 deletion app/views/katello/sync_management/_controls.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
</a>
</div>
<% end %>
<div id="sync_toggle_cont" class="fl table-action">
<div id="sync_toggle_cont" class="fl table-action" data-spinner-asset-path="<%= asset_path('spinner.gif') %>">
<input id="sync_toggle" type="checkbox"/>
<label for="sync_toggle">
<%= _('Active only') %>
Expand Down
1 change: 1 addition & 0 deletions config/routes/overrides.rb
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ def matches?(request)
match '/bulk/module_streams' => 'hosts_bulk_actions#module_streams', :via => :post
match '/bulk/change_content_source' => 'hosts_bulk_actions#change_content_source', :via => :put
match '/subscriptions/' => 'host_subscriptions#create', :via => :post
match '/host_packages/installed_packages' => 'host_packages#installed_packages', :via => :get
end

resources :packages, :only => [:index], :controller => :host_packages do
Expand Down
4 changes: 2 additions & 2 deletions katello.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ Gem::Specification.new do |gem|
gem.add_dependency "rest-client"

gem.add_dependency "rabl"
gem.add_dependency "foreman-tasks", ">= 9.1"
gem.add_dependency "foreman_remote_execution", ">= 7.1.0"
gem.add_dependency "foreman-tasks", ">= 9.2.3", "< 10.0"
gem.add_dependency "foreman_remote_execution", ">= 13.2.5", "< 14.0.0"
gem.add_dependency "dynflow", ">= 1.6.1"
gem.add_dependency "activerecord-import"
gem.add_dependency "stomp"
Expand Down
3 changes: 2 additions & 1 deletion lib/katello/permission_creator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,8 @@ def product_permissions
:repo_errata,
:repo_compare_errata,
:repo_compare_packages],
'katello/api/v2/repository_sets' => [:index, :show, :available_repositories, :auto_complete_search]
'katello/api/v2/repository_sets' => [:index, :show, :available_repositories, :auto_complete_search],
'katello/api/v2/host_packages' => [:installed_packages]
},
:resource_type => 'Katello::Product',
:finder_scope => :readable
Expand Down
2 changes: 1 addition & 1 deletion lib/katello/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module Katello
VERSION = "4.14.0.rc2".freeze
VERSION = "4.14.0.rc3".freeze
end
14 changes: 14 additions & 0 deletions test/controllers/api/v2/api_controller_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,20 @@ def test_scoped_search_full_results_false
assert_equal(2, response[:results].length)
end

def test_scoped_search_casts_to_integer
params = { full_result: 'false', page: '1', per_page: '2' }
@controller.stubs(:params).returns(params)

response = @controller.scoped_search(@query, @default_sort[0], @default_sort[1], @options)
refute_empty response[:results], "results"
assert_nil response[:error], "error"
assert_equal 1, response[:page], "page"
assert_kind_of(Integer, response[:page])
assert_equal 2, response[:per_page], "per page"
assert_kind_of(Integer, response[:per_page])
assert_equal(2, response[:results].length)
end

def test_scoped_search_no_results
params = { :search => "asdfasdf" }
@controller.stubs(:params).returns(params)
Expand Down
45 changes: 39 additions & 6 deletions test/controllers/api/v2/host_packages_controller_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,9 @@ def permissions
def setup
setup_controller_defaults_api
login_user(users(:admin))
@request.env['HTTP_ACCEPT'] = 'application/json'

@host = hosts(:one)
@content_facet = katello_content_facets(:content_facet_one)
@host.content_facet = @content_facet

set_request_headers
setup_hosts
setup_installed_packages
setup_foreman_routes
permissions
end
Expand All @@ -33,6 +30,22 @@ def test_index
assert_response :success
end

def test_installed_packages
response = get :installed_packages

assert_response :success
assert_template layout: "katello/api/v2/layouts/collection"
assert_template "katello/api/v2/host_packages/installed_packages"

response_data = JSON.parse(response.body)
results = response_data['results'] || []

assert_includes results.map { |rpm| rpm['name'] }, @rpm.name
assert_equal InstalledPackage.first.name, results[0]['name']
assert_equal InstalledPackage.second.name, results[0]['name']
assert_operator results.size, :<, InstalledPackage.all.count
end

def test_include_latest_upgradable
HostPackagePresenter.expects(:with_latest).with(anything, @host)

Expand All @@ -59,5 +72,25 @@ def test_view_permissions
get :index, params: { :host_id => @host.id }
end
end

private

def set_request_headers
@request.env['HTTP_ACCEPT'] = 'application/json'
end

def setup_hosts
@host = hosts(:one)
@content_facet = katello_content_facets(:content_facet_one)
@host.content_facet = @content_facet
end

def setup_installed_packages
@rpm = katello_rpms(:one)
@rpm2 = katello_rpms(:two)
@host.installed_packages << Katello::InstalledPackage.create(name: @rpm.name, nvra: @rpm.nvra, version: @rpm.version, release: @rpm.release, nvrea: @rpm.nvrea, arch: @rpm.arch)
@host.installed_packages << Katello::InstalledPackage.create(name: @rpm.name, nvra: @rpm2.nvra, version: @rpm2.version, release: @rpm2.release, nvrea: @rpm2.nvrea, arch: @rpm2.arch)
@host.reload
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,14 @@ const katelloPackageRemoveParams = ({ hostname, packageName }) =>
feature: REX_FEATURES.KATELLO_PACKAGE_REMOVE,
});

const katelloPackagesRemoveParams = ({ hostname, search, descriptionFormat }) =>
baseParams({
hostname,
inputs: { [PACKAGES_SEARCH_QUERY]: search },
feature: REX_FEATURES.KATELLO_PACKAGES_REMOVE_BY_SEARCH,
descriptionFormat,
});

const katelloPackageRemoveBySearchParams = ({
hostname, hostSearch, search, descriptionFormat,
}) =>
Expand Down Expand Up @@ -209,6 +217,16 @@ export const removePackage = ({ hostname, packageName }) => post({
errorToast,
});

// Used by packages wizard
export const removePackages = ({ hostname, search, descriptionFormat }) => post({
type: API_OPERATIONS.POST,
key: REX_JOB_INVOCATIONS_KEY,
url: foremanApi.getApiUrl('/job_invocations'),
params: katelloPackagesRemoveParams({ hostname, search, descriptionFormat }),
handleSuccess: showRexToast,
errorToast,
});

export const removePackagesBySearch = ({
hostname, hostSearch, search, descriptionFormat,
}) => post({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,9 +188,13 @@ const RepositorySetsTab = () => {
lifecycleEnvironmentLibrary,
contentView,
lifecycleEnvironment,
contentViewEnvironments = [],
} = contentFacet;
const { name: contentViewName } = contentView ?? {};
const { name: lifecycleEnvironmentName } = lifecycleEnvironment ?? {};
const multiEnvHost = contentViewEnvironments.length > 1;
const contentViewEnvironmentNames =
contentViewEnvironments.map(({ candlepin_name: candlepinName }) => candlepinName).join(', ');
const nonLibraryHost = contentViewDefault === false ||
lifecycleEnvironmentLibrary === false;
const [isBulkActionOpen, setIsBulkActionOpen] = useState(false);
Expand Down Expand Up @@ -497,7 +501,8 @@ const RepositorySetsTab = () => {
</Split>
) : null;

const hostEnvText = 'the "{contentViewName}" content view and "{lifecycleEnvironmentName}" environment';
const hostEnvText = multiEnvHost ? 'the host\'s content view environments: {contentViewEnvironmentNames}'
: 'the "{contentViewName}" content view and "{lifecycleEnvironmentName}" lifecycle environment';

const alertText = (toggleGroupState === LIMIT_TO_ENVIRONMENT ?
`Showing only repositories in ${hostEnvText}.` :
Expand Down Expand Up @@ -531,6 +536,7 @@ const RepositorySetsTab = () => {
values={{
contentViewName,
lifecycleEnvironmentName,
contentViewEnvironmentNames,
}}
/>
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,94 @@ test('Can upgrade a package via customized remote execution', async (done) => {
assertNockRequest(statusScope, done);
});

test('Can remove a package via remote execution', async (done) => {
const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl);

const scope = nockInstance
.get(hostPackages)
.query(defaultQuery)
.reply(200, { ...mockPackagesData, results: [firstPackage] });

const removeScope = nockInstance
.post(jobInvocations, {
job_invocation: {
inputs: {
package: firstPackage.name,
},
search_query: `name ^ (${hostname})`,
feature: REX_FEATURES.KATELLO_PACKAGE_REMOVE,
},
})
.reply(201);

const {
getByText,
getAllByText,
getByLabelText,
} = renderWithRedux(<PackagesTab />, renderOptions());

await patientlyWaitFor(() => expect(getAllByText(firstPackage.name)[0]).toBeInTheDocument());

const kebabDropdown = getByLabelText('Actions');
kebabDropdown.click();

const rexAction = getByText('Remove');
await patientlyWaitFor(() => expect(rexAction).toBeInTheDocument());
fireEvent.click(rexAction);

assertNockRequest(autocompleteScope);
assertNockRequest(scope);
assertNockRequest(removeScope, done);
});

test('Can bulk remove a package via remote execution', async (done) => {
const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl);

const scope = nockInstance
.get(hostPackages)
.query(defaultQuery)
.reply(200, mockPackagesData);

const removeScope = nockInstance
.post(jobInvocations, {
job_invocation: {
inputs: {
[PACKAGES_SEARCH_QUERY]: `id ^ (${firstPackage.id},${secondPackage.id})`,
},
search_query: `name ^ (${hostname})`,
feature: REX_FEATURES.KATELLO_PACKAGES_REMOVE_BY_SEARCH,
description_format: 'Remove package(s) chrony, coreutils',
},
})
.reply(201);

const {
getByText,
getAllByText,
getByRole,
getByLabelText,
} = renderWithRedux(<PackagesTab />, renderOptions());

await patientlyWaitFor(() => expect(getAllByText(firstPackage.name)[0]).toBeInTheDocument());

getByRole('checkbox', { name: 'Select row 0' }).click();
expect(getByLabelText('Select row 0').checked).toEqual(true);
getByRole('checkbox', { name: 'Select row 1' }).click();
expect(getByLabelText('Select row 1').checked).toEqual(true);

const kebabDropdown = getByRole('button', { name: 'bulk_actions' });
await patientlyWaitFor(() => expect(kebabDropdown).toBeInTheDocument());
fireEvent.click(kebabDropdown);

const rexAction = getByText('Remove');
await patientlyWaitFor(() => expect(rexAction).toBeInTheDocument());
fireEvent.click(rexAction);

assertNockRequest(autocompleteScope);
assertNockRequest(scope);
assertNockRequest(removeScope, done);
});

test('Can bulk upgrade via remote execution', async (done) => {
const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ const BulkPackagesTable = ({
name: {
title: __('Package'),
wrapper: ({ name, id }) => (
<a target="_blank" href={`/packages/${id}`} rel="noreferrer">{name}</a>
<a target="_blank" href={tableType === 'remove' ? `/packages?search=${name}` : `/packages/${id}`} rel="noreferrer">{name}</a>
),
isSorted: true,
weight: 50,
Expand Down
Loading
Loading