-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathansible-clone.py
executable file
·146 lines (113 loc) · 5.2 KB
/
ansible-clone.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#!/usr/bin/env python3
import argparse
import configparser
import os
import distro
import subprocess
import textwrap
from pwd import getpwuid
def get_become_method():
if distro.id() == 'openbsd':
return "doas"
else:
return "sudo"
def get_installed_packages():
apt_distros = ('debian', 'ubuntu', 'linuxmint')
pacman_distros = ('arch')
dnf_distros = ('centos', 'fedora', 'rhel')
# Get a list of installed packages. Only including manually installed, not dependencies
if distro.id() == 'freebsd':
result = subprocess.run(['pkg', 'query', '-e', '%#r = 0', '%n'], capture_output=True, text=True)
elif distro.id() == 'openbsd':
result = subprocess.run(['pkg_info', '-q', '-m', '-z'], capture_output=True, text=True)
elif distro.id() in apt_distros:
result = subprocess.run(['apt-mark', 'showmanual'], capture_output=True, text=True)
elif distro.id() in pacman_distros:
result = subprocess.run(['pacman', '-Q', '-e', '-t', '-q'], capture_output=True, text=True)
elif distro.id() in dnf_distros:
result = subprocess.run(['dnf', 'repoquery', '--userinstalled', '--qf', '"%{name}"'], capture_output=True, text=True)
return [line.split(' ')[0] for line in result.stdout.splitlines()]
def generate_package_tasks(installed_packages):
# Generate a task to install the specified packages. Ansible will choose the package manager
ansible_pkg_mgr = 'ansible.builtin.package'
package_tasks = []
package_tasks.append(f"- name: Install packages\n {ansible_pkg_mgr}:\n name:\n")
for package in installed_packages:
package_tasks.append(f" - {package}\n")
package_tasks.append(f" state: present\n")
return ' '.join(package_tasks)
def read_config_files(config_paths):
# Read configuration files from the .ini file.
config = configparser.ConfigParser()
config.read(config_paths)
return config
def generate_config_tasks(config):
# Generate a task to copy the specified config files to their paths.
tasks = []
for section in config.sections():
file_path = os.path.expanduser(config[section]['path'])
file_stats = os.stat(file_path)
file_owner = getpwuid(file_stats.st_uid).pw_name
file_perms = file_stats.st_mode
with open(file_path) as f:
content = f.read()
# Escape the file content using YAML block scalar style
escaped_content = textwrap.indent(content, ' ' * 10)
task = f" - name: Copy {file_path}\n" \
f" copy:\n" \
f" dest: {file_path}\n" \
f" owner: {file_owner}\n" \
f" mode: {file_perms}\n" \
f" content: |\n" \
f"{escaped_content}\n"
tasks.append(task)
return tasks
def get_enabled_services():
systemd_distros = ('debian', 'ubuntu', 'linuxmint', 'arch', 'centos', 'rhel', 'fedora')
# Find enabled services. Note that this will find ALL enabled services, including default ones
if distro.id() == 'freebsd':
output = subprocess.check_output(['service', '-e'])
elif distro.id() == 'openbsd':
output = subprocess.check_output(['rcctl', 'ls', 'on'])
elif distro.id() in systemd_distros:
output = subprocess.check_output(['systemctl', 'list-unit-files', '--state=enabled', '--type=service', '--no-legend'])
# Convert the output to a string and split it into lines
output_str = output.decode('utf-8')
lines = output_str.split('\n')
services = [line.split()[0] for line in lines if line.strip()]
# Strip the "/etc/rc.d/" prefix from the service names (needed for FreeBSD)
return [s.replace('/etc/rc.d/', '') for s in services]
def generate_service_tasks(enabled_services):
# Generate a list of Ansible tasks to enable the specified services.
service_tasks = []
for service in enabled_services:
service_tasks.append(f" - name: Enable {service} service\n service:\n name: {service}\n enabled: yes\n")
return service_tasks
def generate_playbook(config_paths, playbook_out):
# Generate the Ansible playbook.
become_method = get_become_method()
installed_packages = get_installed_packages()
package_tasks = generate_package_tasks(installed_packages)
config = read_config_files(config_paths)
config_tasks = generate_config_tasks(config)
enabled_services = get_enabled_services()
service_tasks = generate_service_tasks(enabled_services)
with open(playbook_out, 'w') as f:
f.write(f'''---
- hosts: localhost
become: yes
become_method: {become_method}
tasks:
{package_tasks}
{''.join(config_tasks)}
{''.join(service_tasks)}
''')
def main():
# Will eventually want to make these arguments optional
parser = argparse.ArgumentParser(description='Options for ansible-clone')
parser.add_argument('-c', dest='config_paths', required=True, type=str, help='INI file containing config file paths')
parser.add_argument('-f', dest='output_file', required=True, type=str, help='Output playbook file')
args = parser.parse_args()
generate_playbook(args.config_paths, args.output_file)
if __name__ == '__main__':
main()