foreman_ansible 6.3.3 → 7.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.
- checksums.yaml +4 -4
- data/app/controllers/api/v2/ansible_inventories_controller.rb +1 -1
- data/app/graphql/mutations/ansible_variable_overrides/create.rb +26 -0
- data/app/graphql/mutations/ansible_variable_overrides/delete.rb +38 -0
- data/app/graphql/mutations/ansible_variable_overrides/update.rb +26 -0
- data/app/graphql/mutations/hosts/assign_ansible_roles.rb +37 -0
- data/app/graphql/presenters/ansible_role_presenter.rb +12 -0
- data/app/graphql/presenters/overriden_ansible_variable_presenter.rb +19 -0
- data/app/graphql/types/ansible_role.rb +9 -0
- data/app/graphql/types/ansible_variable.rb +23 -0
- data/app/graphql/types/ansible_variable_override.rb +9 -0
- data/app/graphql/types/inherited_ansible_role.rb +13 -0
- data/app/graphql/types/overriden_ansible_variable.rb +27 -0
- data/app/helpers/foreman_ansible/ansible_reports_helper.rb +35 -54
- data/app/models/concerns/foreman_ansible/host_managed_extensions.rb +23 -4
- data/app/models/concerns/foreman_ansible/hostgroup_extensions.rb +1 -0
- data/app/models/foreman_ansible/ansible_provider.rb +56 -6
- data/app/services/foreman_ansible/ansible_report_importer.rb +2 -2
- data/app/services/foreman_ansible/inventory_creator.rb +1 -1
- data/app/services/foreman_ansible/override_resolver.rb +22 -0
- data/app/views/api/v2/ansible_override_values/index.json.rabl +3 -0
- data/app/views/api/v2/ansible_variables/show.json.rabl +1 -1
- data/app/views/foreman_ansible/ansible_roles/_hostgroup_ansible_roles_button.erb +3 -0
- data/app/views/foreman_ansible/config_reports/_ansible.html.erb +14 -5
- data/app/views/foreman_ansible/job_templates/ansible_roles_-_ansible_default.erb +4 -0
- data/app/views/foreman_ansible/job_templates/convert_to_rhel.erb +6 -2
- data/app/views/foreman_ansible/job_templates/run_openscap_scans_-_ansible_default.erb +20 -0
- data/config/routes.rb +3 -0
- data/db/migrate/20210818083407_fix_ansible_setting_category_to_dsl.rb +5 -0
- data/lib/foreman_ansible/engine.rb +0 -18
- data/lib/foreman_ansible/register.rb +114 -2
- data/lib/foreman_ansible/version.rb +1 -1
- data/package.json +10 -6
- data/test/functional/api/v2/ansible_inventories_controller_test.rb +1 -2
- data/test/graphql/mutations/hosts/assign_ansible_roles_mutation_test.rb +96 -0
- data/test/graphql/queries/ansible_roles_query_test.rb +35 -0
- data/test/unit/ansible_provider_test.rb +3 -6
- data/test/unit/concerns/host_managed_extensions_test.rb +8 -0
- data/test/unit/concerns/hostgroup_extensions_test.rb +6 -0
- data/test/unit/helpers/ansible_reports_helper_test.rb +4 -30
- data/test/unit/services/override_resolver_test.rb +34 -0
- data/webpack/components/AnsibleHostDetail/AnsibleHostDetail.js +59 -0
- data/webpack/components/AnsibleHostDetail/AnsibleHostDetail.scss +6 -0
- data/webpack/components/AnsibleHostDetail/AnsibleHostDetail.test.js +20 -0
- data/webpack/components/AnsibleHostDetail/components/AnsibleHostInventory/AnsibleHostInventory.js +22 -0
- data/webpack/components/AnsibleHostDetail/components/AnsibleHostInventory/AnsibleHostInventory.scss +4 -0
- data/webpack/components/AnsibleHostDetail/components/AnsibleHostInventory/AnsibleHostInventory.test.js +104 -0
- data/webpack/components/AnsibleHostDetail/components/AnsibleHostInventory/index.js +38 -0
- data/webpack/components/AnsibleHostDetail/components/AnsibleVariableOverrides/AnsibleVariableOverrides.scss +3 -0
- data/webpack/components/AnsibleHostDetail/components/AnsibleVariableOverrides/AnsibleVariableOverridesTable.js +238 -0
- data/webpack/components/AnsibleHostDetail/components/AnsibleVariableOverrides/AnsibleVariableOverridesTableHelper.js +111 -0
- data/webpack/components/AnsibleHostDetail/components/AnsibleVariableOverrides/EditableAction.js +161 -0
- data/webpack/components/AnsibleHostDetail/components/AnsibleVariableOverrides/EditableAction.scss +7 -0
- data/webpack/components/AnsibleHostDetail/components/AnsibleVariableOverrides/EditableActionHelper.js +49 -0
- data/webpack/components/AnsibleHostDetail/components/AnsibleVariableOverrides/EditableValue.js +70 -0
- data/webpack/components/AnsibleHostDetail/components/AnsibleVariableOverrides/EditableValueHelper.js +35 -0
- data/webpack/components/AnsibleHostDetail/components/AnsibleVariableOverrides/__test__/AnsibleVariableOverrides.fixtures.js +429 -0
- data/webpack/components/AnsibleHostDetail/components/AnsibleVariableOverrides/__test__/AnsibleVariableOverrides.test.js +71 -0
- data/webpack/components/AnsibleHostDetail/components/AnsibleVariableOverrides/__test__/AnsibleVariableOverridesDelete.test.js +74 -0
- data/webpack/components/AnsibleHostDetail/components/AnsibleVariableOverrides/__test__/AnsibleVariableOverridesUpdate.test.js +188 -0
- data/webpack/components/AnsibleHostDetail/components/AnsibleVariableOverrides/index.js +58 -0
- data/webpack/components/AnsibleHostDetail/components/JobsTab/JobsTabHelper.js +79 -0
- data/webpack/components/AnsibleHostDetail/components/JobsTab/NewRecurringJobHelper.js +106 -0
- data/webpack/components/AnsibleHostDetail/components/JobsTab/NewRecurringJobModal.js +129 -0
- data/webpack/components/AnsibleHostDetail/components/JobsTab/NewRecurringJobModal.scss +7 -0
- data/webpack/components/AnsibleHostDetail/components/JobsTab/PreviousJobsTable.js +103 -0
- data/webpack/components/AnsibleHostDetail/components/JobsTab/RecurringJobsTable.js +96 -0
- data/webpack/components/AnsibleHostDetail/components/JobsTab/__test__/JobsTab.fixtures.js +184 -0
- data/webpack/components/AnsibleHostDetail/components/JobsTab/__test__/JobsTab.test.js +195 -0
- data/webpack/components/AnsibleHostDetail/components/JobsTab/index.js +88 -0
- data/webpack/components/AnsibleHostDetail/components/RolesTab/AllRolesModal/AllRolesTable.js +89 -0
- data/webpack/components/AnsibleHostDetail/components/RolesTab/AllRolesModal/index.js +80 -0
- data/webpack/components/AnsibleHostDetail/components/RolesTab/EditRolesModal/EditRolesForm.js +90 -0
- data/webpack/components/AnsibleHostDetail/components/RolesTab/EditRolesModal/EditRolesModal.scss +3 -0
- data/webpack/components/AnsibleHostDetail/components/RolesTab/EditRolesModal/EditRolesModalHelper.js +40 -0
- data/webpack/components/AnsibleHostDetail/components/RolesTab/EditRolesModal/index.js +82 -0
- data/webpack/components/AnsibleHostDetail/components/RolesTab/RolesTable.js +129 -0
- data/webpack/components/AnsibleHostDetail/components/RolesTab/__test__/EditRoles.test.js +85 -0
- data/webpack/components/AnsibleHostDetail/components/RolesTab/__test__/RolesTab.fixtures.js +180 -0
- data/webpack/components/AnsibleHostDetail/components/RolesTab/__test__/RolesTab.test.js +75 -0
- data/webpack/components/AnsibleHostDetail/components/RolesTab/index.js +51 -0
- data/webpack/components/AnsibleHostDetail/components/SecondaryTabRoutes.js +60 -0
- data/webpack/components/AnsibleHostDetail/components/TabLayout.js +12 -0
- data/webpack/components/AnsibleHostDetail/constants.js +9 -0
- data/webpack/components/AnsibleHostDetail/helpers.js +4 -0
- data/webpack/components/AnsibleHostDetail/index.js +6 -0
- data/webpack/components/AnsibleRolesAndVariables/__test__/AnsibleRolesAndVariablesImport.test.js +15 -10
- data/webpack/components/AnsibleRolesSwitcher/components/AnsibleRole.js +29 -0
- data/webpack/components/AnsibleRolesSwitcher/components/AnsibleRole.test.js +3 -0
- data/webpack/components/AnsibleRolesSwitcher/components/AvailableRolesList.js +2 -1
- data/webpack/components/AnsibleRolesSwitcher/components/__snapshots__/AnsiblePermissionDenied.test.js.snap +2 -0
- data/webpack/components/AnsibleRolesSwitcher/components/__snapshots__/AnsibleRole.test.js.snap +3 -3
- data/webpack/components/AnsibleRolesSwitcher/components/__snapshots__/AssignedRolesList.test.js.snap +4 -4
- data/webpack/components/AnsibleRolesSwitcher/components/__snapshots__/AvailableRolesList.test.js.snap +9 -0
- data/webpack/components/DualList/DualList.scss +3 -0
- data/webpack/components/DualList/ListControls.js +65 -0
- data/webpack/components/DualList/ListHeader.js +16 -0
- data/webpack/components/DualList/ListItem.js +69 -0
- data/webpack/components/DualList/ListPane.js +95 -0
- data/webpack/components/DualList/SelectedStatus.js +21 -0
- data/webpack/components/DualList/index.js +103 -0
- data/webpack/components/ErrorState.js +16 -0
- data/webpack/components/withLoading.js +135 -0
- data/webpack/components/withPagination.js +0 -0
- data/webpack/formHelper.js +131 -0
- data/webpack/globalIdHelper.js +13 -0
- data/webpack/global_index.js +18 -0
- data/webpack/graphql/mutations/assignAnsibleRoles.gql +17 -0
- data/webpack/graphql/mutations/cancelRecurringLogic.gql +12 -0
- data/webpack/graphql/mutations/createAnsibleVariableOverride.gql +28 -0
- data/webpack/graphql/mutations/createJobInvocation.gql +11 -0
- data/webpack/graphql/mutations/deleteAnsibleVariableOverride.gql +17 -0
- data/webpack/graphql/mutations/updateAnsibleVariableOverride.gql +29 -0
- data/webpack/graphql/queries/allAnsibleRoles.gql +13 -0
- data/webpack/graphql/queries/ansibleRoles.gql +13 -0
- data/webpack/graphql/queries/currentUserAttributes.gql +11 -0
- data/webpack/graphql/queries/hostAnsibleRoles.gql +17 -0
- data/webpack/graphql/queries/hostAvailableAnsibleRoles.gql +11 -0
- data/webpack/graphql/queries/hostVariableOverrides.gql +39 -0
- data/webpack/graphql/queries/recurringJobs.gql +28 -0
- data/webpack/helpers/pageParamsHelper.js +40 -0
- data/webpack/helpers/paginationHelper.js +9 -0
- data/webpack/permissionsHelper.js +58 -0
- data/webpack/routes/HostgroupJobs/__test__/HostgroupJobs.fixtures.js +63 -0
- data/webpack/routes/HostgroupJobs/__test__/HostgroupJobs.test.js +112 -0
- data/webpack/routes/HostgroupJobs/index.js +26 -0
- data/webpack/routes/routes.js +10 -0
- data/webpack/testHelper.js +165 -0
- data/webpack/toastHelper.js +4 -0
- metadata +130 -78
- data/app/assets/images/foreman_ansible/Ansible.png +0 -0
- data/app/models/foreman_ansible/fact_name.rb +0 -16
- data/app/models/setting/ansible.rb +0 -106
- data/app/services/foreman_ansible/fact_importer.rb +0 -99
- data/app/services/foreman_ansible/fact_parser.rb +0 -126
- data/app/services/foreman_ansible/fact_sparser.rb +0 -37
- data/app/services/foreman_ansible/operating_system_parser.rb +0 -102
- data/app/services/foreman_ansible/structured_fact_importer.rb +0 -25
- data/test/unit/lib/foreman_ansible_core/ansible_runner_test.rb +0 -51
- data/test/unit/lib/foreman_ansible_core/command_creator_test.rb +0 -64
- data/test/unit/lib/foreman_ansible_core/playbook_runner_test.rb +0 -110
- data/test/unit/services/fact_importer_test.rb +0 -52
- data/test/unit/services/fact_parser_test.rb +0 -281
- data/test/unit/services/fact_sparser_test.rb +0 -24
- data/test/unit/services/structured_fact_importer_test.rb +0 -30
- data/webpack/__mocks__/foremanReact/common/I18n.js +0 -1
- data/webpack/__mocks__/foremanReact/common/helpers.js +0 -13
- data/webpack/__mocks__/foremanReact/components/Pagination/PaginationWrapper.js +0 -2
- data/webpack/__mocks__/foremanReact/components/common/EmptyState.js +0 -5
- data/webpack/__mocks__/foremanReact/components/common/forms/OrderableSelect/helpers.js +0 -5
- data/webpack/__mocks__/foremanReact/redux/API.js +0 -7
- data/webpack/components/AnsibleRolesAndVariables/__test__/__snapshots__/AnsibleRolesAndVariablesImport.test.js.snap +0 -177
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 76cdda389998bc85d45534a8feeb54fde36c671401665e5b337101b952efeae4
|
|
4
|
+
data.tar.gz: df707b59de63cd0cf66f553765a9e9a8e659cf2bdb4049198ce12eaff58f12fd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d54c5b84429025c6f2f8be0914ab870d8f5945ea97430cdb7129dbff4ceaffc3812608c6a020a0284b454c54542dd61d4682bcdab1532bc6a012b30ef0c48cbe
|
|
7
|
+
data.tar.gz: 16628e25e09230f8deeabf013bc0cc4277c271f8efde4d5691fab8a925ba1bac3c94b6b79c929e13dedded52bcd7a6406d474db10f5dd39619991227d9fd00c8
|
|
@@ -90,7 +90,7 @@ module Api
|
|
|
90
90
|
private
|
|
91
91
|
|
|
92
92
|
def schedule_params
|
|
93
|
-
template_name = Setting
|
|
93
|
+
template_name = Setting['ansible_inventory_template']
|
|
94
94
|
@report_template = ReportTemplate.find_by!(:name => template_name)
|
|
95
95
|
params[:id] = @report_template.id
|
|
96
96
|
params[:report_format] = 'json' if params[:report_format].blank?
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module Mutations
|
|
2
|
+
module AnsibleVariableOverrides
|
|
3
|
+
class Create < ::Mutations::CreateMutation
|
|
4
|
+
graphql_name 'CreateAnsibleVariableOverrideMutation'
|
|
5
|
+
description 'Creates Ansible Variable Override'
|
|
6
|
+
|
|
7
|
+
resource_class LookupValue
|
|
8
|
+
|
|
9
|
+
argument :host_id, Int, required: true
|
|
10
|
+
argument :lookup_key_id, Int, required: true
|
|
11
|
+
argument :value, ::Types::RawJson, required: true
|
|
12
|
+
argument :match, String, required: true
|
|
13
|
+
argument :omit, Boolean
|
|
14
|
+
|
|
15
|
+
field :overriden_ansible_variable, ::Types::OverridenAnsibleVariable, :null => true
|
|
16
|
+
|
|
17
|
+
def resolve(host_id:, **kwargs)
|
|
18
|
+
result = super kwargs
|
|
19
|
+
host = Host.find host_id
|
|
20
|
+
vars = AnsibleVariable.where :id => kwargs[:lookup_key_id]
|
|
21
|
+
resolver = ::ForemanAnsible::OverrideResolver.new(host, vars)
|
|
22
|
+
result.merge :overriden_ansible_variable => ::Presenters::OverridenAnsibleVariablePresenter.new(vars.first, resolver)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
module Mutations
|
|
2
|
+
module AnsibleVariableOverrides
|
|
3
|
+
class Delete < ::Mutations::DeleteMutation
|
|
4
|
+
graphql_name 'DeleteAnsibleVariableOverride'
|
|
5
|
+
description 'Deletes Ansible Variable Override'
|
|
6
|
+
|
|
7
|
+
resource_class LookupValue
|
|
8
|
+
|
|
9
|
+
argument :host_id, Int, required: true
|
|
10
|
+
argument :variable_id, Int, required: true
|
|
11
|
+
|
|
12
|
+
field :overriden_ansible_variable, ::Types::OverridenAnsibleVariable, :null => true
|
|
13
|
+
|
|
14
|
+
def resolve(id:, host_id:, variable_id:)
|
|
15
|
+
host = Host.find_by :id => host_id
|
|
16
|
+
variable = AnsibleVariable.find_by :id => variable_id
|
|
17
|
+
return resource_not_found(_('Host not found by id: %s'), host_id) unless host
|
|
18
|
+
return resource_not_found(_('Ansible Variable not found by id: %s'), variable_id) unless variable
|
|
19
|
+
authorize!(host, :view)
|
|
20
|
+
authorize!(variable, :edit)
|
|
21
|
+
|
|
22
|
+
result = super id: id
|
|
23
|
+
resolver = ::ForemanAnsible::OverrideResolver.new(host, [variable.id])
|
|
24
|
+
result.merge :overriden_ansible_variable => ::Presenters::OverridenAnsibleVariablePresenter.new(variable, resolver)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def resource_not_found(message)
|
|
28
|
+
{
|
|
29
|
+
:overriden_ansible_variable => nil,
|
|
30
|
+
:errros => [{
|
|
31
|
+
:path => ['base'],
|
|
32
|
+
:message => message
|
|
33
|
+
}]
|
|
34
|
+
}
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module Mutations
|
|
2
|
+
module AnsibleVariableOverrides
|
|
3
|
+
class Update < ::Mutations::UpdateMutation
|
|
4
|
+
graphql_name 'UpdateAnsibleVariableOverrideMutation'
|
|
5
|
+
description 'Updates Ansible Variable Override'
|
|
6
|
+
|
|
7
|
+
resource_class LookupValue
|
|
8
|
+
|
|
9
|
+
argument :value, ::Types::RawJson, required: true
|
|
10
|
+
argument :match, String, required: false
|
|
11
|
+
argument :omit, Boolean, required: false
|
|
12
|
+
argument :host_id, Int, required: true
|
|
13
|
+
argument :ansible_variable_id, Int, required: true
|
|
14
|
+
|
|
15
|
+
field :overriden_ansible_variable, ::Types::OverridenAnsibleVariable, :null => true
|
|
16
|
+
|
|
17
|
+
def resolve(host_id:, ansible_variable_id:, **kwargs)
|
|
18
|
+
result = super kwargs
|
|
19
|
+
host = Host.find host_id
|
|
20
|
+
vars = AnsibleVariable.where :id => ansible_variable_id
|
|
21
|
+
resolver = ::ForemanAnsible::OverrideResolver.new(host, vars.pluck(:id))
|
|
22
|
+
result.merge :overriden_ansible_variable => ::Presenters::OverridenAnsibleVariablePresenter.new(vars.first, resolver)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
module Mutations
|
|
2
|
+
module Hosts
|
|
3
|
+
class AssignAnsibleRoles < ::Mutations::UpdateMutation
|
|
4
|
+
resource_class Host::Managed
|
|
5
|
+
|
|
6
|
+
argument :ansible_role_ids, [Integer], required: true
|
|
7
|
+
|
|
8
|
+
field :host, Types::Host, 'The updated host.', null: false
|
|
9
|
+
|
|
10
|
+
def resolve(id:, ansible_role_ids:)
|
|
11
|
+
host = load_object_by(id: id)
|
|
12
|
+
authorize!(host, :edit)
|
|
13
|
+
|
|
14
|
+
existing = host.host_ansible_roles
|
|
15
|
+
updated_ids = []
|
|
16
|
+
attrs = []
|
|
17
|
+
|
|
18
|
+
ansible_role_ids.each do |role_id|
|
|
19
|
+
current = existing.find_by :ansible_role_id => role_id
|
|
20
|
+
attrs << { :id => current&.id, :position => attrs.count + 1, :ansible_role_id => role_id }
|
|
21
|
+
updated_ids << current.id if current
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
existing.where.not(:id => updated_ids).each do |item|
|
|
25
|
+
attrs << { :id => item.id, :position => attrs.count + 1, :_destroy => true }
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
host.host_ansible_roles_attributes = attrs
|
|
29
|
+
save_object(host)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def result_key
|
|
33
|
+
:host
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
module Presenters
|
|
2
|
+
class AnsibleRolePresenter
|
|
3
|
+
attr_reader :ansible_role, :inherited
|
|
4
|
+
|
|
5
|
+
delegate :id, :name, :association, :to => :ansible_role
|
|
6
|
+
|
|
7
|
+
def initialize(ansible_role, inherited)
|
|
8
|
+
@ansible_role = ansible_role
|
|
9
|
+
@inherited = inherited
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module Presenters
|
|
2
|
+
class OverridenAnsibleVariablePresenter
|
|
3
|
+
attr_reader :ansible_variable
|
|
4
|
+
|
|
5
|
+
delegate :id, :key, :description, :override?,
|
|
6
|
+
:parameter_type, :hidden_value?, :omit, :required,
|
|
7
|
+
:validator_type, :validator_rule, :default_value,
|
|
8
|
+
:ansible_role, :current_value, :to => :ansible_variable
|
|
9
|
+
|
|
10
|
+
def initialize(ansible_variable, override_resolver)
|
|
11
|
+
@ansible_variable = ansible_variable
|
|
12
|
+
@override_resolver = override_resolver
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def current_value
|
|
16
|
+
@override_resolver.resolve @ansible_variable
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module Types
|
|
2
|
+
class AnsibleVariable < BaseObject
|
|
3
|
+
description 'Ansible Variable'
|
|
4
|
+
|
|
5
|
+
global_id_field :id
|
|
6
|
+
|
|
7
|
+
field :key, String
|
|
8
|
+
field :override, Boolean
|
|
9
|
+
field :description, String
|
|
10
|
+
field :hidden_value, Boolean
|
|
11
|
+
field :parameter_type, String
|
|
12
|
+
field :omit, Boolean
|
|
13
|
+
field :required, Boolean
|
|
14
|
+
field :validator_type, String
|
|
15
|
+
field :validator_rule, String
|
|
16
|
+
field :default_value, ::Types::RawJson
|
|
17
|
+
field :ansible_role_name, String
|
|
18
|
+
|
|
19
|
+
def ansible_role_name
|
|
20
|
+
object.ansible_role.name
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
module Types
|
|
2
|
+
class AnsibleVariableOverride < GraphQL::Types::Relay::BaseObject
|
|
3
|
+
description 'Override value for Ansible Variable'
|
|
4
|
+
|
|
5
|
+
field :value, ::Types::RawJson, :null => false
|
|
6
|
+
field :element, ::Types::RawJson, :null => false
|
|
7
|
+
field :element_name, ::Types::RawJson, :null => false
|
|
8
|
+
end
|
|
9
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module Types
|
|
2
|
+
class OverridenAnsibleVariable < ::Types::AnsibleVariable
|
|
3
|
+
description 'Ansible Variable with an override value for a host'
|
|
4
|
+
model_class ::AnsibleVariable
|
|
5
|
+
|
|
6
|
+
field :current_value, ::Types::AnsibleVariableOverride, :null => true
|
|
7
|
+
field :lookup_values, ::Types::LookupValue.connection_type do
|
|
8
|
+
argument :match, String, required: false
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
field :meta, ::Types::Meta, resolve: (proc do |object|
|
|
12
|
+
{
|
|
13
|
+
:can_edit => ::User.current.can?(object.ansible_variable.permission_name(:edit), object.ansible_variable),
|
|
14
|
+
:can_destroy => ::User.current.can?(object.ansible_variable.permission_name(:destroy), object.ansible_variable)
|
|
15
|
+
}
|
|
16
|
+
end)
|
|
17
|
+
|
|
18
|
+
def lookup_values(match: nil)
|
|
19
|
+
return CollectionLoader.for(object.ansible_variable.class, :lookup_values).load(object.ansible_variable) unless match
|
|
20
|
+
|
|
21
|
+
scope = lambda do |sc|
|
|
22
|
+
sc.where(:match => match)
|
|
23
|
+
end
|
|
24
|
+
CollectionLoader.for(object.ansible_variable.class, :lookup_values, scope).load(object.ansible_variable)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -4,21 +4,19 @@ module ForemanAnsible
|
|
|
4
4
|
# This module takes the config reports stored in Foreman for Ansible and
|
|
5
5
|
# modifies them to be properly presented in views
|
|
6
6
|
module AnsibleReportsHelper
|
|
7
|
-
ANSIBLE_META_KEYS = %w[
|
|
8
|
-
_ansible_parsed _ansible_no_log _ansible_item_result
|
|
9
|
-
_ansible_ignore_errors _ansible_verbose_always _ansible_verbose_override
|
|
10
|
-
].freeze
|
|
11
|
-
ANSIBLE_HIDDEN_KEYS = %w[
|
|
12
|
-
invocation module_args results ansible_facts
|
|
13
|
-
stdout stderr
|
|
14
|
-
].freeze
|
|
15
|
-
|
|
16
7
|
def ansible_module_name(log)
|
|
17
8
|
source_value = log.source&.value
|
|
18
9
|
name = source_value.split(':')[0].strip if source_value&.include?(':')
|
|
19
10
|
name
|
|
20
11
|
end
|
|
21
12
|
|
|
13
|
+
def ansible_task_name(log)
|
|
14
|
+
source_value = log.source&.value
|
|
15
|
+
return source_value || no_data_message unless source_value.include? ':'
|
|
16
|
+
name = source_value.split(':')[1].strip if source_value.include?(':')
|
|
17
|
+
name || no_data_message
|
|
18
|
+
end
|
|
19
|
+
|
|
22
20
|
def ansible_run_in_check_mode?(log)
|
|
23
21
|
log.message&.value == 'check_mode_enabled' if check_mode_log?(log)
|
|
24
22
|
end
|
|
@@ -27,12 +25,36 @@ module ForemanAnsible
|
|
|
27
25
|
log.source&.value == 'check_mode'
|
|
28
26
|
end
|
|
29
27
|
|
|
30
|
-
def
|
|
31
|
-
|
|
28
|
+
def ansible_module_message(log)
|
|
29
|
+
msg_json = parsed_message_json(log)
|
|
30
|
+
module_action = msg_json['module']
|
|
31
|
+
case module_action
|
|
32
|
+
when 'package'
|
|
33
|
+
msg_json['results'].empty? ? msg_json['msg'] : msg_json['results']
|
|
34
|
+
when 'template'
|
|
35
|
+
module_args = msg_json['invocation']['module_args']
|
|
36
|
+
_("Rendered template #{module_args['_original_basename']} to #{msg_json['dest']}")
|
|
37
|
+
when 'service'
|
|
38
|
+
_("Service #{msg_json['name']} #{msg_json['state']} (enabled: #{msg_json['enabled']})")
|
|
39
|
+
when 'group'
|
|
40
|
+
_("User group #{msg_json['name']} #{msg_json['state']}, gid: #{msg_json['gid']}")
|
|
41
|
+
when 'user'
|
|
42
|
+
_("User #{msg_json['name']} #{msg_json['state']}, uid: #{msg_json['uid']}")
|
|
43
|
+
when 'cron'
|
|
44
|
+
module_args = msg_json['invocation']['module_args']
|
|
45
|
+
_("Cron job: #{module_args['minute']} #{module_args['hour']} #{module_args['day']} #{module_args['month']} #{module_args['weekday']} #{module_args['job']} (disabled: #{module_args['disabled']})")
|
|
46
|
+
when 'copy'
|
|
47
|
+
module_args = msg_json['invocation']['module_args']
|
|
48
|
+
_("Copy #{module_args['_original_basename']} to #{msg_json['dest']}")
|
|
49
|
+
when 'command', 'shell'
|
|
50
|
+
msg_json['stdout_lines']
|
|
51
|
+
else
|
|
52
|
+
no_data_message
|
|
53
|
+
end
|
|
32
54
|
end
|
|
33
55
|
|
|
34
|
-
def
|
|
35
|
-
|
|
56
|
+
def no_data_message
|
|
57
|
+
_('No additional data')
|
|
36
58
|
end
|
|
37
59
|
|
|
38
60
|
def ansible_report_origin_icon
|
|
@@ -49,49 +71,8 @@ module ForemanAnsible
|
|
|
49
71
|
false
|
|
50
72
|
end
|
|
51
73
|
|
|
52
|
-
def report_json_viewer(json)
|
|
53
|
-
react_component('ReportJsonViewer', data: json)
|
|
54
|
-
end
|
|
55
|
-
|
|
56
74
|
private
|
|
57
75
|
|
|
58
|
-
def module_invocations(hash)
|
|
59
|
-
invocations = []
|
|
60
|
-
invocations << hash.delete('invocation')
|
|
61
|
-
results = hash.delete('results')
|
|
62
|
-
invocations << results
|
|
63
|
-
invocations = invocations.compact.flatten.map do |ih|
|
|
64
|
-
ih.is_a?(Hash) ? remove_keys(ih) : ih
|
|
65
|
-
end
|
|
66
|
-
invocations
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
def pretty_print_hash(hash)
|
|
70
|
-
prettyp = JSON.pretty_generate(remove_keys(hash))
|
|
71
|
-
prettyp.gsub!(/{\n*/, "\n")
|
|
72
|
-
prettyp.gsub!(/},*\n*/, "\n")
|
|
73
|
-
prettyp.gsub!(/^(\[|\])/, '')
|
|
74
|
-
prettyp.gsub!(/^[\s]*$\n/, '')
|
|
75
|
-
paragraph_style = 'white-space:pre;padding: 2em 0'
|
|
76
|
-
tag(:p, prettyp, :style => paragraph_style)
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
def hash_with_keys_removed(hash)
|
|
80
|
-
new_hash = remove_keys(hash)
|
|
81
|
-
remove_keys(new_hash, ANSIBLE_HIDDEN_KEYS)
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
def remove_keys(hash, keys = ANSIBLE_META_KEYS)
|
|
85
|
-
hash.each do |key, value|
|
|
86
|
-
if value.is_a? Array
|
|
87
|
-
value.each { |h| remove_keys(h) if h.is_a? Hash }
|
|
88
|
-
elsif value.is_a? Hash
|
|
89
|
-
remove_keys(value)
|
|
90
|
-
end
|
|
91
|
-
hash.delete(key) if keys.include? key
|
|
92
|
-
end
|
|
93
|
-
end
|
|
94
|
-
|
|
95
76
|
def parsed_message_json(log)
|
|
96
77
|
JSON.parse(log.message.value)
|
|
97
78
|
rescue StandardError => e
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require '
|
|
3
|
+
require 'resolv'
|
|
4
4
|
module ForemanAnsible
|
|
5
5
|
# Relations to make Host::Managed 'have' ansible roles
|
|
6
6
|
module HostManagedExtensions
|
|
@@ -16,7 +16,7 @@ module ForemanAnsible
|
|
|
16
16
|
:dependent => :destroy
|
|
17
17
|
scoped_search :relation => :ansible_roles, :on => :name,
|
|
18
18
|
:complete_value => true, :rename => :ansible_role,
|
|
19
|
-
:only_explicit => true
|
|
19
|
+
:only_explicit => true, ext_method: :search_by_role
|
|
20
20
|
|
|
21
21
|
before_provision :play_ansible_roles
|
|
22
22
|
audit_associations :ansible_roles
|
|
@@ -30,6 +30,14 @@ module ForemanAnsible
|
|
|
30
30
|
hostgroup.inherited_and_own_ansible_roles
|
|
31
31
|
end
|
|
32
32
|
|
|
33
|
+
def own_ansible_roles
|
|
34
|
+
ansible_roles.where.not(:id => inherited_ansible_roles.pluck(:id))
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def available_ansible_roles
|
|
38
|
+
AnsibleRole.where.not(:id => all_ansible_roles.pluck(:id))
|
|
39
|
+
end
|
|
40
|
+
|
|
33
41
|
# This one should be fixed, disabled for the moment as we're
|
|
34
42
|
# in a rush to get the release out
|
|
35
43
|
def play_ansible_roles
|
|
@@ -39,7 +47,7 @@ module ForemanAnsible
|
|
|
39
47
|
composer.triggering.mode = :future
|
|
40
48
|
composer.triggering.start_at = (
|
|
41
49
|
Time.zone.now +
|
|
42
|
-
Setting
|
|
50
|
+
Setting[:ansible_post_provision_timeout].to_i.seconds
|
|
43
51
|
)
|
|
44
52
|
composer.trigger!
|
|
45
53
|
logger.info("Task for Ansible roles on #{self} before_provision: "\
|
|
@@ -58,12 +66,23 @@ module ForemanAnsible
|
|
|
58
66
|
def import_host(*args)
|
|
59
67
|
host = super(*args)
|
|
60
68
|
hostname = args[0]
|
|
61
|
-
if
|
|
69
|
+
if (Resolv::IPv4::Regex.match?(hostname) || Resolv::IPv6::Regex.match?(hostname)) &&
|
|
62
70
|
(host_nic = Nic::Interface.find_by(:ip => hostname))
|
|
63
71
|
host = host_nic.host
|
|
64
72
|
end
|
|
65
73
|
host
|
|
66
74
|
end
|
|
75
|
+
|
|
76
|
+
def search_by_role(_key, operator, value)
|
|
77
|
+
conditions = sanitize_sql_for_conditions(["ansible_roles.name #{operator} ?", value_to_sql(operator, value)])
|
|
78
|
+
host_ids = ::Host::Managed.joins(:ansible_roles).where(conditions).distinct.pluck(:id)
|
|
79
|
+
hostgroup_ids = ::Hostgroup.unscoped.with_taxonomy_scope.joins(:ansible_roles).where(conditions).map(&:subtree_ids).flatten
|
|
80
|
+
|
|
81
|
+
conds = []
|
|
82
|
+
conds << "hosts.id IN(#{host_ids.join(',')})" if host_ids.present?
|
|
83
|
+
conds << "hosts.hostgroup_id IN(#{hostgroup_ids.uniq.join(',')})" if hostgroup_ids.present?
|
|
84
|
+
{ conditions: conds.join(' OR ').presence || '1 = 0' }
|
|
85
|
+
end
|
|
67
86
|
end
|
|
68
87
|
end
|
|
69
88
|
end
|
|
@@ -13,6 +13,7 @@ module ForemanAnsible
|
|
|
13
13
|
:dependent => :destroy
|
|
14
14
|
accepts_nested_attributes_for :hostgroup_ansible_roles, :allow_destroy => true
|
|
15
15
|
audit_associations :ansible_roles
|
|
16
|
+
include_in_clone :ansible_roles
|
|
16
17
|
|
|
17
18
|
def inherited_ansible_roles
|
|
18
19
|
ancestors.reduce([]) do |roles, hostgroup|
|
|
@@ -18,6 +18,10 @@ if defined? ForemanRemoteExecution
|
|
|
18
18
|
'Ansible'
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
+
def provider_input_namespace
|
|
22
|
+
:ansible
|
|
23
|
+
end
|
|
24
|
+
|
|
21
25
|
def proxy_command_options(template_invocation, host)
|
|
22
26
|
super(template_invocation, host).merge(
|
|
23
27
|
'ansible_inventory' => ::ForemanAnsible::InventoryCreator.new(
|
|
@@ -28,7 +32,8 @@ if defined? ForemanRemoteExecution
|
|
|
28
32
|
template_invocation.template
|
|
29
33
|
),
|
|
30
34
|
:name => host.name,
|
|
31
|
-
:check_mode => host.host_param('ansible_roles_check_mode')
|
|
35
|
+
:check_mode => host.host_param('ansible_roles_check_mode'),
|
|
36
|
+
:cleanup_working_dirs => cleanup_working_dirs?(host)
|
|
32
37
|
)
|
|
33
38
|
end
|
|
34
39
|
|
|
@@ -52,20 +57,65 @@ if defined? ForemanRemoteExecution
|
|
|
52
57
|
host_setting(host, 'remote_execution_effective_user_password')
|
|
53
58
|
end
|
|
54
59
|
|
|
55
|
-
def host_setting(host, setting)
|
|
56
|
-
host.params[setting.to_s] || Setting[setting]
|
|
57
|
-
end
|
|
58
|
-
|
|
59
60
|
def supports_effective_user?
|
|
60
61
|
true
|
|
61
62
|
end
|
|
62
63
|
|
|
64
|
+
def provider_inputs
|
|
65
|
+
[
|
|
66
|
+
ForemanRemoteExecution::ProviderInput.new(
|
|
67
|
+
name: 'tags',
|
|
68
|
+
label: _('Tags'),
|
|
69
|
+
value: '',
|
|
70
|
+
value_type: 'plain',
|
|
71
|
+
description: 'Tags used for Ansible execution'
|
|
72
|
+
),
|
|
73
|
+
ForemanRemoteExecution::ProviderInput.new(
|
|
74
|
+
name: 'tags_flag',
|
|
75
|
+
label: _('Include/Exclude Tags'),
|
|
76
|
+
value: 'include',
|
|
77
|
+
description: 'Option whether to include or exclude tags',
|
|
78
|
+
options: "include\nexclude"
|
|
79
|
+
)
|
|
80
|
+
]
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def provider_inputs_doc
|
|
84
|
+
opts = provider_inputs.find { |input| input.name == 'tags_flag' }.options.split("\n")
|
|
85
|
+
{
|
|
86
|
+
:namespace => provider_input_namespace,
|
|
87
|
+
:opts => { :desc => N_('Ansible provider specific inputs') },
|
|
88
|
+
:children => [
|
|
89
|
+
{
|
|
90
|
+
:name => :tags,
|
|
91
|
+
:type => Array,
|
|
92
|
+
:opts => { :required => false, :desc => N_('A comma separated list of tags to use for Ansible run') }
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
:name => :tags_flag,
|
|
96
|
+
:type => opts,
|
|
97
|
+
:opts => { :required => false, :desc => N_('Include\Exclude tags for Ansible run') }
|
|
98
|
+
}
|
|
99
|
+
]
|
|
100
|
+
}
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def proxy_command_provider_inputs(template_invocation)
|
|
104
|
+
tags = template_invocation.provider_input_values.find_by(:name => 'tags')&.value || ''
|
|
105
|
+
tags_flag = template_invocation.provider_input_values.find_by(:name => 'tags_flag')&.value || ''
|
|
106
|
+
{ :tags => tags, :tags_flag => tags_flag }
|
|
107
|
+
end
|
|
108
|
+
|
|
63
109
|
def proxy_operation_name
|
|
64
110
|
'ansible-runner'
|
|
65
111
|
end
|
|
66
112
|
|
|
67
113
|
def proxy_action_class
|
|
68
|
-
'
|
|
114
|
+
'Proxy::Ansible::TaskLauncher::Playbook::PlaybookRunnerAction'
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def proxy_batch_size
|
|
118
|
+
Setting['foreman_ansible_proxy_batch_size']
|
|
69
119
|
end
|
|
70
120
|
|
|
71
121
|
private
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require '
|
|
3
|
+
require 'resolv'
|
|
4
4
|
module ForemanAnsible
|
|
5
5
|
# Ensures Ansible reports from hosts where the IP was used, are assigned
|
|
6
6
|
# to the right hostname in Foreman
|
|
@@ -10,7 +10,7 @@ module ForemanAnsible
|
|
|
10
10
|
def host
|
|
11
11
|
hostname = name.downcase
|
|
12
12
|
if AnsibleReportScanner.ansible_report?(raw) &&
|
|
13
|
-
|
|
13
|
+
(Resolv::IPv4::Regex.match?(hostname) || Resolv::IPv6::Regex.match?(hostname)) &&
|
|
14
14
|
Nic::Interface.find_by(:ip => hostname)
|
|
15
15
|
@host = Nic::Interface.find_by(:ip => hostname).host
|
|
16
16
|
end
|
|
@@ -103,7 +103,7 @@ module ForemanAnsible
|
|
|
103
103
|
'ansible_port' => host_setting(host, 'remote_execution_ssh_port'),
|
|
104
104
|
'ansible_host' => AnsibleProvider.find_ip_or_hostname(host)
|
|
105
105
|
}
|
|
106
|
-
if @template_invocation.effective_user.present?
|
|
106
|
+
if @template_invocation.effective_user.present? && @template_invocation.effective_user != params['ansible_user']
|
|
107
107
|
params['ansible_become_user'] = @template_invocation.effective_user
|
|
108
108
|
params['ansible_become'] = true
|
|
109
109
|
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module ForemanAnsible
|
|
2
|
+
# Service which resolves override values for hosts
|
|
3
|
+
class OverrideResolver
|
|
4
|
+
attr_reader :overrides, :ansible_variables
|
|
5
|
+
|
|
6
|
+
def initialize(host, variable_ids = [])
|
|
7
|
+
raise(Foreman::Exception.new('OverrideResolver needs a host to resolve overrides')) unless host
|
|
8
|
+
@ansible_variables = if variable_ids.empty?
|
|
9
|
+
AnsibleVariable.where(:ansible_role_id => host.all_ansible_roles, :override => true)
|
|
10
|
+
else
|
|
11
|
+
AnsibleVariable.where(:id => variable_ids, :override => true)
|
|
12
|
+
end
|
|
13
|
+
@overrides = @ansible_variables.values_hash(host).raw
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def resolve(ansible_variable)
|
|
17
|
+
override = @overrides[ansible_variable.id]
|
|
18
|
+
return unless override
|
|
19
|
+
override[ansible_variable.key]
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -10,7 +10,7 @@ attributes :id, :variable, :ansible_role, :ansible_role_id, :description, :overr
|
|
|
10
10
|
node do |ansible_variable|
|
|
11
11
|
{
|
|
12
12
|
:override_values => partial(
|
|
13
|
-
'api/v2/
|
|
13
|
+
'api/v2/ansible_override_values/index',
|
|
14
14
|
:object => ansible_variable.lookup_values
|
|
15
15
|
)
|
|
16
16
|
}
|
|
@@ -5,11 +5,14 @@
|
|
|
5
5
|
display_link_if_authorized(_('Run all Ansible roles'), hash_for_play_roles_hostgroup_path(id: hostgroup), :'data-no-turbolink' => true, title: _('Run all Ansible roles on hosts belonging to this host group'))
|
|
6
6
|
end
|
|
7
7
|
|
|
8
|
+
assign_jobs = link_to(_("Configure Ansible Job"), "/ansible/hostgroups/#{hostgroup.id}", { class: 'la' })
|
|
9
|
+
|
|
8
10
|
actions = [
|
|
9
11
|
display_link_if_authorized(_('Nest'), hash_for_nest_hostgroup_path(:id => hostgroup)),
|
|
10
12
|
display_link_if_authorized(_('Clone'), hash_for_clone_hostgroup_path(:id => hostgroup))
|
|
11
13
|
]
|
|
12
14
|
actions.push play_roles if User.current.can?(:create_job_invocations)
|
|
15
|
+
actions.push assign_jobs if User.current.can?(:view_job_invocations) && User.current.can?(:view_recurring_logics)
|
|
13
16
|
actions.push display_delete_if_authorized(hash_for_hostgroup_path(:id => hostgroup).merge(:auth_object => hostgroup, :authorizer => authorizer), :data => { :confirm => warning_message(hostgroup) })
|
|
14
17
|
|
|
15
18
|
action_buttons(*actions)
|