hammer_cli_foreman_ansible 0.3.4 → 0.4.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/lib/hammer_cli_foreman_ansible/ansible.rb +6 -0
- data/lib/hammer_cli_foreman_ansible/ansible_inventory.rb +52 -0
- data/lib/hammer_cli_foreman_ansible/associated_ansible_role.rb +85 -0
- data/lib/hammer_cli_foreman_ansible/command_extensions/inventory.rb +120 -0
- data/lib/hammer_cli_foreman_ansible/command_extensions.rb +1 -0
- data/lib/hammer_cli_foreman_ansible/host.rb +43 -1
- data/lib/hammer_cli_foreman_ansible/hostgroup.rb +42 -1
- data/lib/hammer_cli_foreman_ansible/version.rb +1 -1
- data/lib/hammer_cli_foreman_ansible.rb +1 -0
- data/test/data/3.3/foreman_api.json +1 -0
- data/test/functional/host_test.rb +200 -0
- data/test/functional/hostgroup_test.rb +200 -0
- data/test/functional/test_helper.rb +11 -0
- data/test/test_helper.rb +16 -2
- metadata +13 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 12f80a5bb288d8683aad9b3629edffbbd32bfb4afdf7aa597e4b370e2c19da58
|
4
|
+
data.tar.gz: 03d9f616b2d17580d15e93cae6fb79e0c6b599091fa4f0ed9cb7d6d2db986cdf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 12f88c7777fae85e77ae1288aafb09e08d569989b7a19bedbc939cbaa0d374161b47e23de3f3a4ec35ae78567982d0dc832f4974a14223d0aed05e76092ff7f1
|
7
|
+
data.tar.gz: 4bf5229134f1ce01c9ab517d5a9adb9281a5b9be0cced399fa78bbe55134e571525e51e9aed1c7802ef464a36162f7965eb3683faa294b89f5f99cf73be19c7f
|
@@ -16,6 +16,12 @@ module HammerCLIForemanAnsible
|
|
16
16
|
'hammer_cli_foreman_ansible/ansible_variables'
|
17
17
|
)
|
18
18
|
|
19
|
+
lazy_subcommand(
|
20
|
+
'inventory',
|
21
|
+
_('Ansible Inventory'),
|
22
|
+
'HammerCLIForemanAnsible::AnsibleInventoryCommand',
|
23
|
+
'hammer_cli_foreman_ansible/ansible_inventory'
|
24
|
+
)
|
19
25
|
autoload_subcommands
|
20
26
|
end
|
21
27
|
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module HammerCLIForemanAnsible
|
4
|
+
class AnsibleInventoryCommand < HammerCLIForeman::Command
|
5
|
+
resource :ansible_inventories
|
6
|
+
|
7
|
+
class HostsCommand < HammerCLIForeman::Command
|
8
|
+
action :hosts
|
9
|
+
command_name 'hosts'
|
10
|
+
option '--as-json', :flag, _('Full response as json')
|
11
|
+
|
12
|
+
def print_data(data)
|
13
|
+
return super unless option_as_json?
|
14
|
+
|
15
|
+
puts JSON.pretty_generate(data)
|
16
|
+
end
|
17
|
+
build_options
|
18
|
+
|
19
|
+
extend_with(HammerCLIForemanAnsible::CommandExtensions::Inventory.new)
|
20
|
+
end
|
21
|
+
|
22
|
+
class HostgroupsCommand < HammerCLIForeman::Command
|
23
|
+
action :hostgroups
|
24
|
+
command_name 'hostgroups'
|
25
|
+
option '--as-json', :flag, _('Full response as json')
|
26
|
+
|
27
|
+
def print_data(data)
|
28
|
+
return super unless option_as_json?
|
29
|
+
|
30
|
+
puts JSON.pretty_generate(data)
|
31
|
+
end
|
32
|
+
build_options
|
33
|
+
|
34
|
+
extend_with(HammerCLIForemanAnsible::CommandExtensions::Inventory.new)
|
35
|
+
end
|
36
|
+
|
37
|
+
class ScheduleCommand < HammerCLIForeman::Command
|
38
|
+
action :schedule
|
39
|
+
command_name 'schedule'
|
40
|
+
|
41
|
+
output do
|
42
|
+
field :job_id, _('Job Id')
|
43
|
+
field :data_url, _('Data URL')
|
44
|
+
end
|
45
|
+
|
46
|
+
build_options
|
47
|
+
end
|
48
|
+
|
49
|
+
autoload_subcommands
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module HammerCLIForemanAnsible
|
2
|
+
module AssociatedAnsibleRole
|
3
|
+
# This method fetches all associated resource (ansible roles) ids
|
4
|
+
# to send them back via :update endpoint of the main resource (host/hostgroup)
|
5
|
+
# We use this array of ids to add or remove direct associations
|
6
|
+
# This method is used to 'reset' associated ids via HammerCLIForeman::[Add|Remove]AssociatedCommand
|
7
|
+
def get_current_ids
|
8
|
+
roles = HammerCLIForeman.record_to_common_format(resource.call(association_name(true), { id: get_identifier }))
|
9
|
+
return ids_to_keep_for_removal(roles) if self.class.command_names.include?('remove')
|
10
|
+
|
11
|
+
ids_to_keep_for_addition(roles)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Since there are no option_sources available to deal with such cases (AssociatedCommand)
|
15
|
+
# Make sure we get id of the provided role before we try to get already associated ones
|
16
|
+
def get_new_ids
|
17
|
+
associated_identifiers = get_associated_identifiers
|
18
|
+
@associated_identifier = get_associated_identifier
|
19
|
+
|
20
|
+
ids = get_current_ids.map(&:to_s)
|
21
|
+
|
22
|
+
required_ids = associated_identifiers.nil? ? [] : associated_identifiers.map(&:to_s)
|
23
|
+
required_ids << @associated_identifier.to_s unless @associated_identifier.nil?
|
24
|
+
|
25
|
+
ids = if self.class.command_names.include?('remove')
|
26
|
+
ids.delete_if { |id| required_ids.include? id }
|
27
|
+
else
|
28
|
+
ids + required_ids
|
29
|
+
end
|
30
|
+
ids.uniq
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
# Treat inherited as we do in UI:
|
36
|
+
# - Don't allow to directly associate them (the role is not available to select)
|
37
|
+
# - If the same role was assigned AND inherited then treat it as it was just assigned (keep it)
|
38
|
+
# - If the role is indirectly associated only then don't associate it directly unless --force provided
|
39
|
+
def ids_to_keep_for_addition(roles)
|
40
|
+
roles.map do |role|
|
41
|
+
# Keep directly associated roles
|
42
|
+
next role['id'] if role['directly_assigned']
|
43
|
+
|
44
|
+
# Host groups can have not inherited and not directly assigned roles in the response.
|
45
|
+
# This means those roles are from hosts, skip them.
|
46
|
+
# Hosts cannot have such case.
|
47
|
+
|
48
|
+
# Pre-check to force stop the command if we're trying to add an already inherited role
|
49
|
+
# (in case we don't have it directly associated as well)
|
50
|
+
if @associated_identifier == role['id'] && role['inherited']
|
51
|
+
next role['id'] if option_force?
|
52
|
+
|
53
|
+
msg = _(
|
54
|
+
'Ansible role %{name} is already inherited from a host group. Please use %{option} for direct association.'
|
55
|
+
) % { name: role['name'], option: '--force' }
|
56
|
+
raise ArgumentError, msg
|
57
|
+
end
|
58
|
+
|
59
|
+
# We skip not directly assigned and inherited
|
60
|
+
# Also skip not inherited for host groups
|
61
|
+
nil
|
62
|
+
end.compact
|
63
|
+
end
|
64
|
+
|
65
|
+
# Treat inherited as we do in UI:
|
66
|
+
# - Don't allow to remove them (the role is not available to select)
|
67
|
+
# - If the same role was assigned AND inherited then treat it as it was just assigned (keep or remove it)
|
68
|
+
# - If the role was inherited only then don't remove it
|
69
|
+
def ids_to_keep_for_removal(roles)
|
70
|
+
roles.map do |role|
|
71
|
+
# Keep or remove later directly associated roles
|
72
|
+
next role['id'] if role['directly_assigned']
|
73
|
+
|
74
|
+
# Pre-check to force stop the command if we're trying to remove not directly assigned role
|
75
|
+
if role['id'] == @associated_identifier
|
76
|
+
raise ArgumentError, _('Ansible role %s is not assigned directly and cannot be removed.') % role['name']
|
77
|
+
end
|
78
|
+
|
79
|
+
# We skip not directly assigned and inherited
|
80
|
+
# Also skip not inherited for host groups
|
81
|
+
nil
|
82
|
+
end.compact
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module HammerCLIForemanAnsible
|
4
|
+
module CommandExtensions
|
5
|
+
class Inventory < HammerCLI::CommandExtensions
|
6
|
+
output do |definition|
|
7
|
+
definition.append do
|
8
|
+
from 'foreman' do
|
9
|
+
field :hostname, _('Name')
|
10
|
+
field :fqdn, _('FQDN')
|
11
|
+
field :hostgroup, _('Host Group')
|
12
|
+
field :location, _('Location')
|
13
|
+
field :organization, _('Organization')
|
14
|
+
field :domainname, _('Domain')
|
15
|
+
field :foreman_domain_description, _('Foreman domain description')
|
16
|
+
field :owner_name, _('Owner name')
|
17
|
+
field :owner_email, _('Owner email')
|
18
|
+
field :ssh_authorized_keys, _('SSH authorized keys')
|
19
|
+
field :root_pw, _('Root password')
|
20
|
+
field :foreman_config_groups, _('Foreman config groups')
|
21
|
+
field :puppetmaster, _('Puppet master')
|
22
|
+
field :foreman_env, _('Puppet environment')
|
23
|
+
|
24
|
+
collection :foreman_subnets, _('Subnets') do
|
25
|
+
field :name, _('Name')
|
26
|
+
field :network, _('Network')
|
27
|
+
field :mask, _('Mask')
|
28
|
+
field :gateway, _('Gateway')
|
29
|
+
field :dns_primary, _('Primary DNS')
|
30
|
+
field :dns_secondary, _('Secondary DNS')
|
31
|
+
field :from, _('From')
|
32
|
+
field :to, _('To')
|
33
|
+
field :boot_mode, _('Boot mode')
|
34
|
+
field :ipam, _('IPAM')
|
35
|
+
field :vlanid, _('VLAN ID')
|
36
|
+
field :mtu, _('MTU')
|
37
|
+
field :nic_delay, _('NIC delay')
|
38
|
+
field :network_type, _('Network type')
|
39
|
+
field :description, _('Description')
|
40
|
+
end
|
41
|
+
|
42
|
+
collection :foreman_interfaces, _('Network interfaces') do
|
43
|
+
field :name, _('Interface Name')
|
44
|
+
field :identifier, _('Identifier')
|
45
|
+
field :attrs, _('Attributes'),Fields::Field, hide_blank: true
|
46
|
+
field :mac, _('MAC address')
|
47
|
+
field :ip, _('IPv4 address'), Fields::Field, hide_blank: true
|
48
|
+
field :ip6, _('IPv6 address'), Fields::Field, hide_blank: true
|
49
|
+
field :virtual, _('Virtual'), Fields::Boolean
|
50
|
+
field :link, _('Link'), Fields::Boolean
|
51
|
+
field :managed, _('Managed'), Fields::Boolean
|
52
|
+
field :primary, _('Primary'), Fields::Boolean
|
53
|
+
field :provision, _('Provision'), Fields::Boolean
|
54
|
+
field :subnet6, _('IPv6 subnet')
|
55
|
+
field :tag, _('Tag')
|
56
|
+
field :attached_to, _('Attached to')
|
57
|
+
field :type, _('Type')
|
58
|
+
field :attached_devices, _('Attached devices')
|
59
|
+
from 'subnet' do
|
60
|
+
label _('Subnet'), hide_blank: true do
|
61
|
+
field :name, _('Name')
|
62
|
+
field :network, _('Network')
|
63
|
+
field :mask, _('Mask')
|
64
|
+
field :gateway, _('Gateway')
|
65
|
+
field :dns_primary, _('Primary DNS')
|
66
|
+
field :dns_secondary, _('Secondary DNS')
|
67
|
+
field :from, _('From')
|
68
|
+
field :to, _('To')
|
69
|
+
field :boot_mode, _('Boot mode')
|
70
|
+
field :ipam, _('IPAM')
|
71
|
+
field :vlanid, _('VLAN ID')
|
72
|
+
field :mtu, _('MTU')
|
73
|
+
field :nic_delay, _('NIC delay')
|
74
|
+
field :network_type, _('Network type')
|
75
|
+
field :description, _('Description')
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
collection :foreman_users, _('Foreman Users'), numbered: false do
|
81
|
+
field :firstname, _('First name')
|
82
|
+
field :lastname, _('Last name')
|
83
|
+
field :mail, _('Email')
|
84
|
+
field :description, _('Description')
|
85
|
+
field :fullname, _('Full name')
|
86
|
+
field :ssh_authorized_keys, _('SSH authorized keys')
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
collection :foreman_ansible_roles, _('Foreman Ansible Roles'), numbered: false do
|
91
|
+
field :name, _('Role')
|
92
|
+
end
|
93
|
+
|
94
|
+
field :ansible_roles_check_mode, _('Ansible role check mode'), Fields::Boolean
|
95
|
+
field :host_packages, _('Host packages')
|
96
|
+
field :host_registration_insights, _('Host registration insights'), Fields::Boolean
|
97
|
+
field :host_registration_remote_execution, _('Host registration remote execution'), Fields::Boolean
|
98
|
+
field :remote_execution_ssh_keys, _('Remote execution ssh keys')
|
99
|
+
field :remote_execution_ssh_user, _('Remote execution ssh user')
|
100
|
+
field :remote_execution_effective_user_method, _('Remote execution effective user method')
|
101
|
+
field :remote_execution_connect_by_ip, _('Remote execution connect by IP'), Fields::Boolean
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
before_print do |data, cmd_obj|
|
106
|
+
unless cmd_obj.option_as_json?
|
107
|
+
new_data = data['all']['hosts'].each_with_object([]) do |hostname, arr|
|
108
|
+
data['_meta']['hostvars'][hostname]['foreman']['foreman_users'] = data['_meta']['hostvars'][hostname]['foreman']['foreman_users']&.map { |u| u[1] }
|
109
|
+
data['_meta']['hostvars'][hostname]['foreman_ansible_roles'] = data['_meta']['hostvars'][hostname]['foreman_ansible_roles']&.map { |r| { 'name' => r } }
|
110
|
+
arr << {
|
111
|
+
'hostname' => hostname
|
112
|
+
}.merge(data['_meta']['hostvars'][hostname])
|
113
|
+
end
|
114
|
+
data.clear
|
115
|
+
data['results'] = new_data
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
@@ -11,7 +11,10 @@ module HammerCLIForemanAnsible
|
|
11
11
|
class ListCommand < HammerCLIForeman::ListCommand
|
12
12
|
action :ansible_roles
|
13
13
|
|
14
|
-
output
|
14
|
+
output(HammerCLIForemanAnsible::AnsibleRolesCommand::ListCommand.output_definition) do
|
15
|
+
field :inherited, _('Inherited'), Fields::Boolean
|
16
|
+
field :directly_assigned, _('Directly assigned'), Fields::Boolean
|
17
|
+
end
|
15
18
|
|
16
19
|
build_options
|
17
20
|
end
|
@@ -35,6 +38,45 @@ module HammerCLIForemanAnsible
|
|
35
38
|
|
36
39
|
build_options
|
37
40
|
end
|
41
|
+
|
42
|
+
class AddAnsibleRoleCommand < HammerCLIForeman::AddAssociatedCommand
|
43
|
+
prepend HammerCLIForemanAnsible::AssociatedAnsibleRole
|
44
|
+
|
45
|
+
command_name 'add'
|
46
|
+
associated_resource :ansible_roles
|
47
|
+
desc _('Associate an Ansible role')
|
48
|
+
|
49
|
+
option '--force', :flag, _('Associate the Ansible role even if it already is associated indirectly')
|
50
|
+
|
51
|
+
success_message _('Ansible role has been associated.')
|
52
|
+
failure_message _('Could not associate the Ansible role')
|
53
|
+
|
54
|
+
validate_options do
|
55
|
+
any(:option_name, :option_id).required
|
56
|
+
any(:option_ansible_role_name, :option_ansible_role_id).required
|
57
|
+
end
|
58
|
+
|
59
|
+
build_options
|
60
|
+
end
|
61
|
+
|
62
|
+
class RemoveAnsibleRoleCommand < HammerCLIForeman::RemoveAssociatedCommand
|
63
|
+
prepend HammerCLIForemanAnsible::AssociatedAnsibleRole
|
64
|
+
|
65
|
+
command_name 'remove'
|
66
|
+
associated_resource :ansible_roles
|
67
|
+
desc _('Disassociate an Ansible role')
|
68
|
+
|
69
|
+
success_message _('Ansible role has been disassociated.')
|
70
|
+
failure_message _('Could not disassociate the Ansible role')
|
71
|
+
|
72
|
+
validate_options do
|
73
|
+
any(:option_name, :option_id).required
|
74
|
+
any(:option_ansible_role_name, :option_ansible_role_id).required
|
75
|
+
end
|
76
|
+
|
77
|
+
build_options
|
78
|
+
end
|
79
|
+
|
38
80
|
autoload_subcommands
|
39
81
|
end
|
40
82
|
end
|
@@ -11,7 +11,10 @@ module HammerCLIForemanAnsible
|
|
11
11
|
class ListCommand < HammerCLIForeman::ListCommand
|
12
12
|
action :ansible_roles
|
13
13
|
|
14
|
-
output
|
14
|
+
output(HammerCLIForemanAnsible::AnsibleRolesCommand::ListCommand.output_definition) do
|
15
|
+
field :inherited, _('Inherited'), Fields::Boolean
|
16
|
+
field :directly_assigned, _('Directly assigned'), Fields::Boolean
|
17
|
+
end
|
15
18
|
|
16
19
|
build_options
|
17
20
|
end
|
@@ -36,6 +39,44 @@ module HammerCLIForemanAnsible
|
|
36
39
|
build_options
|
37
40
|
end
|
38
41
|
|
42
|
+
class AddAnsibleRoleCommand < HammerCLIForeman::AddAssociatedCommand
|
43
|
+
prepend HammerCLIForemanAnsible::AssociatedAnsibleRole
|
44
|
+
|
45
|
+
command_name 'add'
|
46
|
+
associated_resource :ansible_roles
|
47
|
+
desc _('Associate an Ansible role')
|
48
|
+
|
49
|
+
option '--force', :flag, _('Associate the Ansible role even if it already is associated indirectly')
|
50
|
+
|
51
|
+
success_message _('Ansible role has been associated.')
|
52
|
+
failure_message _('Could not associate the Ansible role')
|
53
|
+
|
54
|
+
validate_options do
|
55
|
+
any(:option_name, :option_title, :option_id).required
|
56
|
+
any(:option_ansible_role_name, :option_ansible_role_id).required
|
57
|
+
end
|
58
|
+
|
59
|
+
build_options
|
60
|
+
end
|
61
|
+
|
62
|
+
class RemoveAnsibleRoleCommand < HammerCLIForeman::RemoveAssociatedCommand
|
63
|
+
prepend HammerCLIForemanAnsible::AssociatedAnsibleRole
|
64
|
+
|
65
|
+
command_name 'remove'
|
66
|
+
associated_resource :ansible_roles
|
67
|
+
desc _('Disassociate an Ansible role')
|
68
|
+
|
69
|
+
success_message _('Ansible role has been disassociated.')
|
70
|
+
failure_message _('Could not disassociate the Ansible role')
|
71
|
+
|
72
|
+
validate_options do
|
73
|
+
any(:option_name, :option_title, :option_id).required
|
74
|
+
any(:option_ansible_role_name, :option_ansible_role_id).required
|
75
|
+
end
|
76
|
+
|
77
|
+
build_options
|
78
|
+
end
|
79
|
+
|
39
80
|
autoload_subcommands
|
40
81
|
end
|
41
82
|
end
|
@@ -8,6 +8,7 @@ module HammerCLIForemanAnsible
|
|
8
8
|
require 'hammer_cli_foreman_ansible/i18n'
|
9
9
|
require 'hammer_cli_foreman_ansible/ansible'
|
10
10
|
require 'hammer_cli_foreman_ansible/ansible_roles'
|
11
|
+
require 'hammer_cli_foreman_ansible/associated_ansible_role'
|
11
12
|
require 'hammer_cli_foreman_ansible/host'
|
12
13
|
require 'hammer_cli_foreman_ansible/hostgroup'
|
13
14
|
|