jumpserver/apps/ops/ansible/inventory.py

339 lines
14 KiB
Python
Raw Normal View History

2017-03-05 12:53:24 +00:00
# ~*~ coding: utf-8 ~*~
2022-09-29 12:44:45 +00:00
import json
2022-10-08 11:12:04 +00:00
import os
import re
merge: with pam (#14911) * perf: change i18n * perf: pam * perf: change translate * perf: add check account * perf: add date field * perf: add account filter * perf: remove some js * perf: add account status action * perf: update pam * perf: 修改 discover account * perf: update filter * perf: update gathered account * perf: 修改账号同步 * perf: squash migrations * perf: update pam * perf: change i18n * perf: update account risk * perf: 更新风险发现 * perf: remove css * perf: Admin connection token * perf: Add a switch to check connectivity after changing the password, and add a custom ssh command for push tasks * perf: Modify account migration files * perf: update pam * perf: remove to check account dir * perf: Admin connection token * perf: update check account * perf: 优化发送结果 * perf: update pam * perf: update bulk update create * perf: prepaire using thread timer for bulk_create_decorator * perf: update bulk create decorator * perf: 优化 playbook manager * perf: 优化收集账号的报表 * perf: Update poetry * perf: Update Dockerfile with new base image tag * fix: Account migrate 0012 file * perf: 修改备份 * perf: update pam * fix: Expand resource_type filter to include raw type * feat: PAM Service (#14552) * feat: PAM Service * perf: import package name --------- Co-authored-by: jiangweidong <1053570670@qq.com> * perf: Change secret dashboard (#14551) Co-authored-by: feng <1304903146@qq.com> * perf: update migrations * perf: 修改支持 pam * perf: Change secret record table dashboard * perf: update status * fix: Automation send report * perf: Change secret report * feat: windows accounts gather * perf: update change status * perf: Account backup * perf: Account backup report * perf: Account migrate * perf: update service to application * perf: update migrations * perf: update logo * feat: oracle accounts gather (#14571) * feat: oracle accounts gather * feat: sqlserver accounts gather * feat: postgresql accounts gather * feat: mysql accounts gather --------- Co-authored-by: wangruidong <940853815@qq.com> * feat: mongodb accounts gather * perf: Change secret * perf: Migrate * perf: Merge conflicting migration files * perf: Change secret * perf: Automation filter org * perf: Account push * perf: Random secret string * perf: Enhance SQL query and update risk handling in accounts * perf: Ticket filter assignee_id * perf: 修改 account remote * perf: 修改一些 adhoc 任务 * perf: Change secret * perf: Remove push account extra api * perf: update status * perf: The entire organization can view activity log * fix: risk field check * perf: add account details api * perf: add demo mode * perf: Delete gather_account * perf: Perfect solution to account version problem * perf: Update status action to handle multiple accounts * perf: Add GatherAccountDetailField and update serializers * perf: Display account history in combination with password change records * perf: Lina translate * fix: Update mysql_filter to handle nested user info * perf: Admin connection token validate_permission account * perf: copy move account * perf: account filter risk * perf: account risk filter * perf: Copy move account failed message * fix: gather account sync account to asset * perf: Pam dashboard * perf: Account dashboard total accounts * perf: Pam dashboard * perf: Change secret filter account secret_reset * perf: 修改 risk filter * perf: pam translate * feat: Check for leaked duplicate passwords. (#14711) * feat: Check for leaked duplicate passwords. * perf: Use SQLite instead of txt as leak password database --------- Co-authored-by: jiangweidong <1053570670@qq.com> Co-authored-by: 老广 <ibuler@qq.com> * perf: merge with remote * perf: Add risk change_password_add handle * perf: Pam dashboard * perf: check account manager import * perf: 重构扫描 * perf: 修改 db * perf: Gather account manager * perf: update change db lib * perf: dashboard * perf: Account gather * perf: 修改 asset get queryset * perf: automation report * perf: Pam account * perf: Pam dashboard api * perf: risk add account * perf: 修改 risk check * perf: Risk account * perf: update risk add reopen action * perf: add pylintrc * Revert "perf: automation report" This reverts commit 22aee542071638bcefae5a244bcabf76f794d7c3. * perf: check account engine * perf: Perf: Optimism Gather Report Style * Perf: Remove unuser actions * Perf: Perf push account * perf: perf gather account * perf: Automation report * perf: Push account recorder * perf: Push account record * perf: Pam dashboard * perf: perf * perf: update intergration * perf: integrations application detail add account tab page * feat: Custom change password supports configuration of interactive items * perf: Go and Python demo code * perf: Custom secret change * perf: add user filter * perf: translate * perf: Add demo code docs * perf: update some i18n * perf: update some i18n * perf: Add Java, Node, Go, and cURL demo code * perf: Translate * perf: Change secret translate * perf: Translate * perf: update some i18n * perf: translate * perf: Ansible playbook * perf: update some choice * perf: update some choice * perf: update account serializer remote unused code * perf: conflict * perf: update import --------- Co-authored-by: ibuler <ibuler@qq.com> Co-authored-by: feng <1304903146@qq.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: wangruidong <940853815@qq.com> Co-authored-by: jiangweidong <1053570670@qq.com> Co-authored-by: feng626 <57284900+feng626@users.noreply.github.com> Co-authored-by: zhaojisen <1301338853@qq.com>
2025-02-21 08:39:57 +00:00
import sys
2022-10-09 12:54:11 +00:00
from collections import defaultdict
2022-09-29 12:44:45 +00:00
2022-10-08 11:51:29 +00:00
from django.utils.translation import gettext as _
2022-10-08 08:55:14 +00:00
__all__ = ['JMSInventory']
2017-12-10 16:29:25 +00:00
class JMSInventory:
def __init__(
self, assets, account_policy='privileged_first',
account_prefer='root,Administrator', host_callback=None,
exclude_localhost=False, task_type=None, protocol=None
):
"""
:param assets:
2022-10-14 08:33:24 +00:00
:param account_prefer: account username name if not set use account_policy
2022-11-01 03:52:51 +00:00
:param account_policy: privileged_only, privileged_first, skip
"""
2022-09-29 12:44:45 +00:00
self.assets = self.clean_assets(assets)
self.account_prefer = self.get_account_prefer(account_prefer)
2022-09-29 12:44:45 +00:00
self.account_policy = account_policy
2022-10-28 08:25:16 +00:00
self.host_callback = host_callback
self.exclude_hosts = {}
2023-02-13 11:22:52 +00:00
self.exclude_localhost = exclude_localhost
self.task_type = task_type
self.protocol = protocol
2022-09-29 12:44:45 +00:00
@staticmethod
def clean_assets(assets):
from assets.models import Asset
asset_ids = [asset.id for asset in assets]
2022-10-20 12:34:15 +00:00
assets = Asset.objects.filter(id__in=asset_ids, is_active=True) \
2022-09-29 12:44:45 +00:00
.prefetch_related('platform', 'domain', 'accounts')
return assets
@staticmethod
def group_by_platform(assets):
groups = defaultdict(list)
for asset in assets:
groups[asset.platform].append(asset)
return groups
@staticmethod
def get_gateway_ssh_settings(gateway):
platform = gateway.platform
try:
protocol = platform.protocols.get(name='ssh')
except platform.protocols.model.DoesNotExist:
return {}
return protocol.setting
def make_proxy_command(self, gateway, path_dir):
2022-09-29 12:44:45 +00:00
proxy_command_list = [
"ssh", "-o", "Port={}".format(gateway.port),
"-o", "StrictHostKeyChecking=no",
f"{gateway.username}@{gateway.address}"
2022-09-29 12:44:45 +00:00
]
setting = self.get_gateway_ssh_settings(gateway)
if setting.get('nc', False):
proxy_command_list.extend(["nc", "-w", "10", "%h", "%p"])
else:
proxy_command_list.extend(["-W", "%h:%p", "-q"])
2022-09-29 12:44:45 +00:00
if gateway.password:
proxy_command_list.insert(0, f"sshpass -p {gateway.password}")
2022-09-29 12:44:45 +00:00
if gateway.private_key:
proxy_command_list.append(f"-i {gateway.get_private_key_path(path_dir)}")
2022-09-29 12:44:45 +00:00
proxy_command = f"-o ProxyCommand='{' '.join(proxy_command_list)}'"
2022-09-29 12:44:45 +00:00
return {"ansible_ssh_common_args": proxy_command}
2022-10-14 08:33:24 +00:00
@staticmethod
def make_account_ansible_vars(account, path_dir):
2022-10-14 08:33:24 +00:00
var = {
'ansible_user': account.username,
}
if not account.secret:
return var
2022-10-14 08:33:24 +00:00
if account.secret_type == 'password':
var['ansible_password'] = account.escape_jinja2_syntax(account.secret)
2022-10-14 08:33:24 +00:00
elif account.secret_type == 'ssh_key':
var['ansible_ssh_private_key_file'] = account.get_private_key_path(path_dir)
2022-10-14 08:33:24 +00:00
return var
@staticmethod
def make_custom_become_ansible_vars(account, su_from_auth, path_dir):
su_method = su_from_auth['ansible_become_method']
var = {
2024-06-14 08:49:32 +00:00
'jms_custom_become': True,
'jms_custom_become_method': su_method,
'jms_custom_become_user': account.su_from.username,
'jms_custom_become_password': account.escape_jinja2_syntax(account.su_from.secret),
'jms_custom_become_private_key_path': account.su_from.get_private_key_path(path_dir)
}
return var
@staticmethod
def make_protocol_setting_vars(host, protocols):
# 针对 ssh 协议的特殊处理
for p in protocols:
if p.name == 'ssh':
if hasattr(p, 'setting'):
setting = getattr(p, 'setting')
host['old_ssh_version'] = setting.get('old_ssh_version', False)
def make_account_vars(self, host, asset, account, automation, protocol, platform, gateway, path_dir):
2023-05-12 07:37:13 +00:00
from accounts.const import AutomationTypes
2022-10-14 08:33:24 +00:00
if not account:
host['error'] = _("No account available")
return host
2023-03-30 06:58:20 +00:00
port = protocol.port if protocol else 22
2022-10-14 08:33:24 +00:00
host['ansible_host'] = asset.address
2023-03-30 06:58:20 +00:00
host['ansible_port'] = port
2022-10-14 08:33:24 +00:00
su_from = account.su_from
if platform.su_enabled and su_from:
su_from_auth = account.get_ansible_become_auth()
host.update(su_from_auth)
host.update(self.make_custom_become_ansible_vars(account, su_from_auth, path_dir))
elif platform.su_enabled and not su_from and \
self.task_type in (AutomationTypes.change_secret, AutomationTypes.push_account):
host.update(self.make_account_ansible_vars(account, path_dir))
host['ansible_become'] = True
host['ansible_become_user'] = 'root'
host['ansible_become_password'] = account.escape_jinja2_syntax(account.secret)
2022-10-14 08:33:24 +00:00
else:
host.update(self.make_account_ansible_vars(account, path_dir))
2022-10-14 08:33:24 +00:00
2024-04-22 03:27:48 +00:00
if platform.is_huawei():
host['ansible_connection'] = 'network_cli'
host['ansible_network_os'] = 'ce'
2022-10-14 08:33:24 +00:00
if gateway:
2023-03-30 06:58:20 +00:00
ansible_connection = host.get('ansible_connection', 'ssh')
if ansible_connection in ('local', 'winrm', 'rdp'):
2024-06-14 08:49:32 +00:00
host['jms_gateway'] = {
2023-03-30 06:58:20 +00:00
'address': gateway.address, 'port': gateway.port,
'username': gateway.username, 'secret': gateway.password,
'private_key_path': gateway.get_private_key_path(path_dir)
2023-03-30 06:58:20 +00:00
}
host['jms_asset']['port'] = port
else:
ansible_ssh_common_args = self.make_proxy_command(gateway, path_dir)
host['jms_asset'].update(ansible_ssh_common_args)
host.update(ansible_ssh_common_args)
2023-03-22 07:26:23 +00:00
def get_primary_protocol(self, ansible_config, protocols):
2023-03-30 06:58:20 +00:00
invalid_protocol = type('protocol', (), {'name': 'null', 'port': 0})
ansible_connection = ansible_config.get('ansible_connection')
2023-03-30 06:58:20 +00:00
# 数值越小,优先级越高,若用户在 ansible_config 中配置了,则提高用户配置方式的优先级
protocol_priority = {'ssh': 10, 'winrm': 9, ansible_connection: 1}
if self.protocol:
protocol_priority.update({self.protocol: 0})
2023-03-30 06:58:20 +00:00
protocol_sorted = sorted(protocols, key=lambda x: protocol_priority.get(x.name, 999))
protocol = protocol_sorted[0] if protocol_sorted else invalid_protocol
return protocol
@staticmethod
def fill_ansible_config(ansible_config, protocol):
if protocol.name in ('ssh', 'winrm', 'rdp'):
2023-03-30 06:58:20 +00:00
ansible_config['ansible_connection'] = protocol.name
2023-04-03 01:57:40 +00:00
if protocol.name == 'winrm':
if protocol.setting.get('use_ssl', False):
ansible_config['ansible_winrm_scheme'] = 'https'
ansible_config['ansible_winrm_transport'] = 'ssl'
ansible_config['ansible_winrm_server_cert_validation'] = 'ignore'
else:
ansible_config['ansible_winrm_scheme'] = 'http'
2023-07-12 03:05:01 +00:00
ansible_config['ansible_winrm_transport'] = 'ntlm'
ansible_config['ansible_winrm_connection_timeout'] = 120
return ansible_config
def asset_to_host(self, asset, account, automation, protocols, platform, path_dir):
2023-03-30 06:58:20 +00:00
try:
ansible_config = dict(automation.ansible_config)
except (AttributeError, TypeError):
ansible_config = {}
2023-04-03 02:17:00 +00:00
protocol = self.get_primary_protocol(ansible_config, protocols)
2023-03-22 06:15:25 +00:00
tp, category = asset.type, asset.category
name = re.sub(r'[ \[\]/]', '_', asset.name)
secret_info = {k: v for k, v in asset.secret_info.items() if v}
2022-10-09 12:54:11 +00:00
host = {
'name': name,
merge: with pam (#14911) * perf: change i18n * perf: pam * perf: change translate * perf: add check account * perf: add date field * perf: add account filter * perf: remove some js * perf: add account status action * perf: update pam * perf: 修改 discover account * perf: update filter * perf: update gathered account * perf: 修改账号同步 * perf: squash migrations * perf: update pam * perf: change i18n * perf: update account risk * perf: 更新风险发现 * perf: remove css * perf: Admin connection token * perf: Add a switch to check connectivity after changing the password, and add a custom ssh command for push tasks * perf: Modify account migration files * perf: update pam * perf: remove to check account dir * perf: Admin connection token * perf: update check account * perf: 优化发送结果 * perf: update pam * perf: update bulk update create * perf: prepaire using thread timer for bulk_create_decorator * perf: update bulk create decorator * perf: 优化 playbook manager * perf: 优化收集账号的报表 * perf: Update poetry * perf: Update Dockerfile with new base image tag * fix: Account migrate 0012 file * perf: 修改备份 * perf: update pam * fix: Expand resource_type filter to include raw type * feat: PAM Service (#14552) * feat: PAM Service * perf: import package name --------- Co-authored-by: jiangweidong <1053570670@qq.com> * perf: Change secret dashboard (#14551) Co-authored-by: feng <1304903146@qq.com> * perf: update migrations * perf: 修改支持 pam * perf: Change secret record table dashboard * perf: update status * fix: Automation send report * perf: Change secret report * feat: windows accounts gather * perf: update change status * perf: Account backup * perf: Account backup report * perf: Account migrate * perf: update service to application * perf: update migrations * perf: update logo * feat: oracle accounts gather (#14571) * feat: oracle accounts gather * feat: sqlserver accounts gather * feat: postgresql accounts gather * feat: mysql accounts gather --------- Co-authored-by: wangruidong <940853815@qq.com> * feat: mongodb accounts gather * perf: Change secret * perf: Migrate * perf: Merge conflicting migration files * perf: Change secret * perf: Automation filter org * perf: Account push * perf: Random secret string * perf: Enhance SQL query and update risk handling in accounts * perf: Ticket filter assignee_id * perf: 修改 account remote * perf: 修改一些 adhoc 任务 * perf: Change secret * perf: Remove push account extra api * perf: update status * perf: The entire organization can view activity log * fix: risk field check * perf: add account details api * perf: add demo mode * perf: Delete gather_account * perf: Perfect solution to account version problem * perf: Update status action to handle multiple accounts * perf: Add GatherAccountDetailField and update serializers * perf: Display account history in combination with password change records * perf: Lina translate * fix: Update mysql_filter to handle nested user info * perf: Admin connection token validate_permission account * perf: copy move account * perf: account filter risk * perf: account risk filter * perf: Copy move account failed message * fix: gather account sync account to asset * perf: Pam dashboard * perf: Account dashboard total accounts * perf: Pam dashboard * perf: Change secret filter account secret_reset * perf: 修改 risk filter * perf: pam translate * feat: Check for leaked duplicate passwords. (#14711) * feat: Check for leaked duplicate passwords. * perf: Use SQLite instead of txt as leak password database --------- Co-authored-by: jiangweidong <1053570670@qq.com> Co-authored-by: 老广 <ibuler@qq.com> * perf: merge with remote * perf: Add risk change_password_add handle * perf: Pam dashboard * perf: check account manager import * perf: 重构扫描 * perf: 修改 db * perf: Gather account manager * perf: update change db lib * perf: dashboard * perf: Account gather * perf: 修改 asset get queryset * perf: automation report * perf: Pam account * perf: Pam dashboard api * perf: risk add account * perf: 修改 risk check * perf: Risk account * perf: update risk add reopen action * perf: add pylintrc * Revert "perf: automation report" This reverts commit 22aee542071638bcefae5a244bcabf76f794d7c3. * perf: check account engine * perf: Perf: Optimism Gather Report Style * Perf: Remove unuser actions * Perf: Perf push account * perf: perf gather account * perf: Automation report * perf: Push account recorder * perf: Push account record * perf: Pam dashboard * perf: perf * perf: update intergration * perf: integrations application detail add account tab page * feat: Custom change password supports configuration of interactive items * perf: Go and Python demo code * perf: Custom secret change * perf: add user filter * perf: translate * perf: Add demo code docs * perf: update some i18n * perf: update some i18n * perf: Add Java, Node, Go, and cURL demo code * perf: Translate * perf: Change secret translate * perf: Translate * perf: update some i18n * perf: translate * perf: Ansible playbook * perf: update some choice * perf: update some choice * perf: update account serializer remote unused code * perf: conflict * perf: update import --------- Co-authored-by: ibuler <ibuler@qq.com> Co-authored-by: feng <1304903146@qq.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: wangruidong <940853815@qq.com> Co-authored-by: jiangweidong <1053570670@qq.com> Co-authored-by: feng626 <57284900+feng626@users.noreply.github.com> Co-authored-by: zhaojisen <1301338853@qq.com>
2025-02-21 08:39:57 +00:00
'local_python_interpreter': sys.executable,
2022-10-10 12:56:13 +00:00
'jms_asset': {
2022-10-10 05:56:42 +00:00
'id': str(asset.id), 'name': asset.name, 'address': asset.address,
'type': tp, 'category': category,
2023-03-30 06:58:20 +00:00
'protocol': protocol.name, 'port': protocol.port,
'spec_info': asset.spec_info, 'secret_info': secret_info,
2022-10-09 12:54:11 +00:00
'protocols': [{'name': p.name, 'port': p.port} for p in protocols],
'origin_address': asset.address
2022-10-09 12:54:11 +00:00
},
2022-10-20 12:34:15 +00:00
'jms_account': {
2022-10-10 12:56:13 +00:00
'id': str(account.id), 'username': account.username,
'secret': account.escape_jinja2_syntax(account.secret),
'secret_type': account.secret_type, 'private_key_path': account.get_private_key_path(path_dir)
2022-10-10 12:56:13 +00:00
} if account else None
2022-10-09 12:54:11 +00:00
}
self.make_protocol_setting_vars(host, protocols)
protocols = host['jms_asset']['protocols']
host['jms_asset'].update({f"{p['name']}_port": p['port'] for p in protocols})
if host['jms_account'] and tp == 'oracle':
host['jms_account']['mode'] = 'sysdba' if account.privileged else None
2023-03-30 06:58:20 +00:00
ansible_config = self.fill_ansible_config(ansible_config, protocol)
2022-10-13 09:47:29 +00:00
host.update(ansible_config)
2022-10-27 10:53:10 +00:00
2022-09-29 12:44:45 +00:00
gateway = None
if not asset.is_gateway and asset.domain:
2022-09-29 12:44:45 +00:00
gateway = asset.domain.select_gateway()
2023-03-30 06:58:20 +00:00
self.make_account_vars(
host, asset, account, automation, protocol, platform, gateway, path_dir
2023-03-30 06:58:20 +00:00
)
2022-09-29 12:44:45 +00:00
return host
@staticmethod
def sorted_accounts(accounts):
2023-03-16 11:06:50 +00:00
connectivity_score = {'ok': 2, '-': 1, 'err': 0}
sort_key = lambda x: (x.privileged, connectivity_score.get(x.connectivity, 0), x.date_updated)
accounts_sorted = sorted(accounts, key=sort_key, reverse=True)
return accounts_sorted
def get_asset_sorted_accounts(self, asset):
accounts = list(asset.accounts.filter(is_active=True))
accounts_sorted = self.sorted_accounts(accounts)
return accounts_sorted
@staticmethod
def get_account_prefer(account_prefer):
account_usernames = []
if isinstance(account_prefer, str) and account_prefer:
account_usernames = list(map(lambda x: x.lower(), account_prefer.split(',')))
return account_usernames
def get_refer_account(self, accounts):
account = None
if accounts:
account = list(filter(
lambda a: a.username.lower() in self.account_prefer, accounts
))
account = account[0] if account else None
return account
2022-09-29 12:44:45 +00:00
def select_account(self, asset):
2023-03-16 11:06:50 +00:00
accounts = self.get_asset_sorted_accounts(asset)
if not accounts:
return None
2022-10-08 11:51:29 +00:00
2023-03-16 11:06:50 +00:00
refer_account = self.get_refer_account(accounts)
if refer_account:
return refer_account
2022-09-29 12:44:45 +00:00
2023-03-16 11:06:50 +00:00
account_selected = accounts[0]
if self.account_policy == 'skip':
return None
elif self.account_policy == 'privileged_first':
2022-11-01 03:52:51 +00:00
return account_selected
2023-03-16 11:06:50 +00:00
elif self.account_policy == 'privileged_only' and account_selected.privileged:
return account_selected
else:
return None
2022-09-29 12:44:45 +00:00
@staticmethod
2023-04-03 01:57:40 +00:00
def set_platform_protocol_setting_to_asset(asset, platform_protocols):
asset_protocols = asset.protocols.all()
for p in asset_protocols:
setattr(p, 'setting', platform_protocols.get(p.name, {}))
return asset_protocols
2022-10-20 12:34:15 +00:00
def generate(self, path_dir):
2022-09-29 12:44:45 +00:00
hosts = []
platform_assets = self.group_by_platform(self.assets)
for platform, assets in platform_assets.items():
automation = platform.automation
platform_protocols = {
p['name']: p['setting'] for p in platform.protocols.values('name', 'setting')
}
2022-10-13 09:47:29 +00:00
for asset in assets:
2023-04-03 01:57:40 +00:00
protocols = self.set_platform_protocol_setting_to_asset(asset, platform_protocols)
2022-09-29 12:44:45 +00:00
account = self.select_account(asset)
host = self.asset_to_host(asset, account, automation, protocols, platform, path_dir)
2022-10-12 10:08:57 +00:00
2022-10-08 11:51:29 +00:00
if not automation.ansible_enabled:
2022-10-12 10:08:57 +00:00
host['error'] = _('Ansible disabled')
2022-10-28 08:25:16 +00:00
if self.host_callback is not None:
host = self.host_callback(
2022-10-12 10:08:57 +00:00
host, asset=asset, account=account,
2022-10-20 12:34:15 +00:00
platform=platform, automation=automation,
path_dir=path_dir
2022-10-12 10:08:57 +00:00
)
if isinstance(host, list):
hosts.extend(host)
2022-10-09 12:54:11 +00:00
else:
hosts.append(host)
2022-09-29 12:44:45 +00:00
2022-10-17 03:22:21 +00:00
exclude_hosts = list(filter(lambda x: x.get('error'), hosts))
2022-10-08 11:51:29 +00:00
if exclude_hosts:
print(_("Skip hosts below:"))
2022-10-10 05:56:42 +00:00
for i, host in enumerate(exclude_hosts, start=1):
2022-10-12 10:08:57 +00:00
print("{}: [{}] \t{}".format(i, host['name'], host['error']))
self.exclude_hosts[host['name']] = host['error']
2022-10-17 03:22:21 +00:00
hosts = list(filter(lambda x: not x.get('error'), hosts))
2022-09-29 12:44:45 +00:00
data = {'all': {'hosts': {}}}
for host in hosts:
name = host.pop('name')
data['all']['hosts'][name] = host
2023-08-01 02:39:34 +00:00
if not self.exclude_localhost:
data['all']['hosts'].update({
'localhost': {
'ansible_host': '127.0.0.1',
'ansible_connection': 'local'
}
})
2022-10-08 11:12:04 +00:00
return data
def write_to_file(self, path):
path_dir = os.path.dirname(path)
if not os.path.exists(path_dir):
os.makedirs(path_dir, 0o700, True)
2022-10-24 12:24:56 +00:00
data = self.generate(path_dir)
2022-09-29 12:44:45 +00:00
with open(path, 'w') as f:
f.write(json.dumps(data, indent=4))