Skip to content
Open
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
module ForemanPuppet
module Api
module V2
class HostsBulkActionsController < ::ForemanPuppet::Api::V2::PuppetBaseController
include ::Api::V2::BulkHostsExtension
before_action :find_editable_hosts, only: %i[change_puppet_proxy remove_puppet_proxy]
before_action :find_smart_proxy, only: %i[change_puppet_proxy]

def_param_group :bulk_params do
param :organization_id, :number, required: true, desc: N_('ID of the organization')
param :included, Hash, required: true, action_aware: true do
param :search, String, required: false, desc: N_('Search string for hosts to perform an action on')
param :ids, Array, required: false, desc: N_('List of host ids to perform an action on')
end
param :excluded, Hash, required: true, action_aware: true do
param :ids, Array, required: false, desc: N_('List of host ids to exclude and not run an action on')
end
end

api :PUT, '/hosts/bulk/change_puppet_proxy', N_('Change Puppet (CA) Proxy')
param_group :bulk_params
param :proxy_id, :number, required: true, desc: N_('ID of the Puppet proxy to reassign the hosts to')
param :ca_proxy, :bool, required: true, desc: N_('True, if Puppet CA proxy should be changed instead of the Puppet proxy')
def change_puppet_proxy
::BulkHostsManager.new(hosts: @hosts).change_puppet_proxy(@proxy, params[:ca_proxy])
process_response(true, { message: n_('Updated host: changed Puppet proxy', 'Updated hosts: changed Puppet proxy', @hosts.count) })
end

api :PUT, '/hosts/bulk/remove_puppet_proxy', N_('Remove Puppet (CA) Proxy')
param_group :bulk_params
param :ca_proxy, :bool, required: true, desc: N_('True, if Puppet CA proxy should be removed instead of the Puppet proxy')
def remove_puppet_proxy
::BulkHostsManager.new(hosts: @hosts).change_puppet_proxy(nil, params[:ca_proxy])
process_response(true, { message: n_('Updated host: removed Puppet proxy', 'Updated hosts: removedPuppet proxy', @hosts.count) })
end

private

def find_editable_hosts
find_bulk_hosts(:edit_hosts, params)
end

def find_smart_proxy
@proxy = SmartProxy.find_by(id: params[:smart_proxy_id])
if @proxy.nil?
render json: {
error: {
message: _('The Puppet proxy you have provided cannot be found.'),
},
}, status: :unprocessable_entity
false
else
true
end
end
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
module ForemanPuppet
module Extensions
module BulkHostsManager
extend ActiveSupport::Concern

def change_puppet_proxy(proxy, ca_proxy)
@hosts.each do |host|
if ca_proxy
host.puppet_ca_proxy = proxy
else
host.puppet_proxy = proxy
end
host.save(validate: false)
rescue StandardError => e
message = format(_('Failed to set %{proxy_type} proxy for %{host}.'), host: host, proxy_type: proxy_type)
Foreman::Logging.exception(message, e)
end
end
end
end
end
3 changes: 3 additions & 0 deletions config/api_routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
namespace :api, defaults: { format: 'json' } do
scope '(:apiv)', module: :v2, defaults: { apiv: 'v2' }, apiv: /v1|v2/, constraints: ApiConstraints.new(version: 2, default: true) do
constraints(id: %r{[^/]+}) do
match 'hosts/bulk/change_puppet_proxy', to: 'hosts_bulk_actions#change_puppet_proxy', via: [:put]
match 'hosts/bulk/remove_puppet_proxy', to: 'hosts_bulk_actions#remove_puppet_proxy', via: [:put]

resources :config_groups, except: %i[new edit]

resources :hosts, only: [] do
Expand Down
1 change: 1 addition & 0 deletions lib/foreman_puppet/engine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class Engine < ::Rails::Engine
::ProvisioningTemplate.include ForemanPuppet::Extensions::ProvisioningTemplate

::HostCounter.prepend ForemanPuppet::Extensions::HostCounter
::BulkHostsManager.include ForemanPuppet::Extensions::BulkHostsManager

::Api::V2::BaseController.include ForemanPuppet::Extensions::ApiBaseController
::Api::V2::HostsController.include ForemanPuppet::Extensions::ApiV2HostsController
Expand Down
42 changes: 42 additions & 0 deletions webpack/global_index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
import React from 'react';
import { addGlobalFill } from 'foremanReact/components/common/Fill/GlobalFill';
import { registerReducer } from 'foremanReact/common/MountingService';
import { registerColumns } from 'foremanReact/components/HostsIndex/Columns/core';
import { translate as __ } from 'foremanReact/common/I18n';
import reducers from './src/reducers';
import { registerFills } from './src/Extends/Fills';
import { registerLegacy } from './legacy';
import HostsIndexActionsBar from './src/Extends/Hosts/ActionsBar';
import BulkChangePuppetProxy from './src/Extends/Hosts/BulkActions/BulkChangePuppetProxy';
import BulkChangePuppetCAProxy from './src/Extends/Hosts/BulkActions/BulkChangePuppetCAProxy';
import BulkRemovePuppetProxy from './src/Extends/Hosts/BulkActions/BulkRemovePuppetProxy';
import BulkRemovePuppetCAProxy from './src/Extends/Hosts/BulkActions/BulkRemovePuppetCAProxy';

// register reducers
registerReducer('puppet', reducers);
Expand All @@ -29,4 +36,39 @@ puppetHostsIndexColumns.forEach(column => {
column.categoryKey = 'puppet';
});

addGlobalFill(
'hosts-index-kebab',
'puppet-hosts-index-kebab',
<HostsIndexActionsBar key="puppet-hosts-index-kebab" />,
100
);

addGlobalFill(
'_all-hosts-modals',
'BulkChangePuppetProxy',
<BulkChangePuppetProxy key="bulk-change-puppet-proxy" />,
100
);

addGlobalFill(
'_all-hosts-modals',
'BulkChangePuppetCAProxy',
<BulkChangePuppetCAProxy key="bulk-change-puppet-ca-proxy" />,
100
);

addGlobalFill(
'_all-hosts-modals',
'BulkRemovePuppetCAProxy',
<BulkRemovePuppetCAProxy key="bulk-remove-puppet-ca-proxy" />,
100
);

addGlobalFill(
'_all-hosts-modals',
'BulkRemovePuppetProxy',
<BulkRemovePuppetProxy key="bulk-remove-puppet-proxy" />,
100
);

registerColumns(puppetHostsIndexColumns);
14 changes: 14 additions & 0 deletions webpack/src/Extends/Hosts/ActionsBar/ActionsBar.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.disabled-menu-item-span {
width: 25em;
display: flex;
flex-direction: row;
}

.disabled-menu-item-p {
margin-left: 0.6em;
word-break: normal;
}

.disabled-menu-item-icon {
font-size: small;
}
105 changes: 105 additions & 0 deletions webpack/src/Extends/Hosts/ActionsBar/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import React, { useContext, useEffect } from 'react';
import PropTypes from 'prop-types';
import { useDispatch } from 'react-redux';
import { Menu, MenuItem, MenuContent, MenuList } from '@patternfly/react-core';
import { BanIcon } from '@patternfly/react-icons';
import { translate as __ } from 'foremanReact/common/I18n';
import { ForemanHostsIndexActionsBarContext } from 'foremanReact/components/HostsIndex';
import { useForemanModal } from 'foremanReact/components/ForemanModal/ForemanModalHooks';
import { addModal } from 'foremanReact/components/ForemanModal/ForemanModalActions';
import './ActionsBar.scss';

const DisabledMenuItemDescription = ({ disabledReason }) => (
<span className="disabled-menu-item-span">
<span className="disabled-menu-item-icon">
<BanIcon />
</span>
<p className="disabled-menu-item-p">{disabledReason}</p>
</span>
);

DisabledMenuItemDescription.propTypes = {
disabledReason: PropTypes.string.isRequired,
};

const HostActionsBar = () => {
const { selectedCount, setMenuOpen } = useContext(
ForemanHostsIndexActionsBarContext
);

const dispatch = useDispatch();
useEffect(() => {
[
'bulk-change-puppet-proxy',
'bulk-change-puppet-ca-proxy',
'bulk-remove-puppet-proxy',
'bulk-remove-puppet-ca-proxy',
].forEach(id => {
dispatch(addModal({ id }));
});
}, [dispatch]);
const { setModalOpen: openBulkChangePuppetProxy } = useForemanModal({
id: 'bulk-change-puppet-proxy',
});
const { setModalOpen: openBulkChangePuppetCAProxy } = useForemanModal({
id: 'bulk-change-puppet-ca-proxy',
});
const { setModalOpen: openBulkRemovePuppetProxy } = useForemanModal({
id: 'bulk-remove-puppet-proxy',
});
const { setModalOpen: openBulkRemovePuppetCAProxy } = useForemanModal({
id: 'bulk-remove-puppet-ca-proxy',
});

return (
<MenuItem
itemId="content-flyout-item"
key="content-flyout"
isDisabled={selectedCount === 0}
flyoutMenu={
<Menu ouiaId="content-flyout-menu" onSelect={() => setMenuOpen(false)}>
<MenuContent>
<MenuList>
<MenuItem
itemId="bulk-change-puppet-proxy-menu-item"
key="bulk-change-puppet-proxy-menu-item"
onClick={openBulkChangePuppetProxy}
isDisabled={selectedCount === 0}
>
{__('Change Puppet Proxy')}
</MenuItem>
<MenuItem
itemId="bulk-remove-puppet-proxy-menu-item"
key="bulk-remove-puppet-proxy-menu-item"
onClick={openBulkRemovePuppetProxy}
isDisabled={selectedCount === 0}
>
{__('Remove Puppet Proxy')}
</MenuItem>
<MenuItem
itemId="bulk-change-puppet-ca-proxy-menu-item"
key="bulk-change-puppet-ca-proxy-menu-item"
onClick={openBulkChangePuppetCAProxy}
isDisabled={selectedCount === 0}
>
{__('Change Puppet CA Proxy')}
</MenuItem>
<MenuItem
itemId="bulk-remove-puppet-ca-proxy-menu-item"
key="bulk-remove-puppet-ca-proxy-menu-item"
onClick={openBulkRemovePuppetCAProxy}
isDisabled={selectedCount === 0}
>
{__('Remove Puppet CA Proxy')}
</MenuItem>
</MenuList>
</MenuContent>
</Menu>
}
>
{__('Puppet')}
</MenuItem>
);
};

export default HostActionsBar;
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { APIActions } from 'foremanReact/redux/API';
import { foremanUrl } from 'foremanReact/common/helpers';

export const SMART_PROXY_KEY = 'SMART_PROXY_KEY';
export const BULK_CHANGE_PUPPET_CA_PROXY_KEY = 'BULK_CHANGE_PUPPET_CA_PROXY';
export const BULK_CHANGE_PUPPET_PROXY_KEY = 'BULK_CHANGE_PUPPET_PROXY';

export const fetchSmartProxies = () => {
const url = foremanUrl('/api/smart_proxies');
return APIActions.get({
key: SMART_PROXY_KEY,
url,
params: {
per_page: 'all',
},
});
};

export const bulkChangePuppetProxy = (
params,
handleSuccess,
handleError,
key
) => {
const url = foremanUrl(
`/foreman_puppet/api/v2/hosts/bulk/change_puppet_proxy`
);
return APIActions.put({
key,
url,
handleSuccess,
handleError,
params,
});
};

export default fetchSmartProxies;
Loading
Loading