Skip to content

Commit 204f6e1

Browse files
author
tkrah
committed
Add support to create backups which can be used as variables by Ansible
1 parent d2f3d7f commit 204f6e1

File tree

1 file changed

+150
-67
lines changed

1 file changed

+150
-67
lines changed

bin/backup_foreman

Lines changed: 150 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -8,108 +8,177 @@ import getopt
88
import os
99

1010
import yaml
11+
1112
from foreman.foreman import *
1213

1314

15+
def ensure_dir(dir):
16+
if not os.path.exists(dir):
17+
os.makedirs(dir)
18+
19+
20+
def remove_keys_from_dict(keys, data):
21+
for key in keys:
22+
if key in data:
23+
data.pop(key)
24+
return data
25+
26+
27+
def clear_data(data, invalid_keys):
28+
if isinstance(data, list):
29+
for i in range(len(data)):
30+
data[i] = clear_data(data=data[i], invalid_keys=invalid_keys)
31+
elif isinstance(data, dict):
32+
data = remove_keys_from_dict(keys=invalid_keys, data=data)
33+
for key in data:
34+
data[key] = clear_data(data[key], invalid_keys=invalid_keys)
35+
return data
36+
37+
1438
class ForemanBackup:
15-
def __init__(self, hostname, port, username, password, katello_support=False, backup_dir='.'):
16-
self.foreman = Foreman(hostname, port, username, password)
17-
self.backup_dir = backup_dir
18-
self.katello_support = katello_support
39+
def __init__(self, **kwargs):
40+
self.foreman = Foreman(kwargs.get('hostname'),
41+
kwargs.get('port'),
42+
kwargs.get('username'),
43+
kwargs.get('password'))
44+
self.backup_dir = kwargs.get('backup_dir', '.')
45+
self.katello_support = kwargs.get('katello_support', False)
46+
47+
def get_resources(self, type, resource_function):
48+
result = list()
49+
try:
50+
resources = resource_function()
51+
for i in range(len(resources)):
52+
item = resources[i]
53+
if 'id' in item:
54+
try:
55+
resource = self.get_resource(type=type, id=resources[i].get('id'))
56+
except ForemanError as e:
57+
# There seems to be a bug in Foreman 1.7.3 whereas the API reports 404
58+
# while executing a get request on organizations/:id
59+
# API: http://theforeman.org/api/apidoc/v2/organizations/show.html
60+
if e.status_code == 404:
61+
resource = item
62+
else:
63+
resource = item
64+
result.append(resource)
65+
return result
66+
except ForemanError as e:
67+
print('Error on getting resource {0}'.format(e.message))
68+
exit(1)
1969

20-
def backup(self, resource, resource_function):
21-
"""Backup Foreman resource as YAML file into a directory.
70+
def get_resource(self, type, id):
71+
return self.foreman.get_resource(resource_type=type, resource_id=id)
2272

23-
A new directory named <resource> will be created inside <backup_dir>. Each
73+
def write_resources(self, type, items, backup_dir):
74+
"""Backup Foreman type as YAML file into a directory.
75+
76+
A new directory named <type> will be created inside <backup_dir>. Each
2477
resource fetched by <resource_function> will be saved in an own YAML file
25-
called <resource_name>.yaml in <backup_dir>/<resource>.
78+
called <resource_name>.yaml in <backup_dir>/<type>.
2679
2780
Args:
2881
backup_dir (str): Directory where to create the backup files
29-
resource (str): Name of the resource to backup (e.g. 'architectures')
82+
type (str): Name of the resource to backup (e.g. 'architectures')
3083
resource_function (def): Name of function to call to get a dict of resources
3184
"""
32-
backup_dir = os.path.join(self.backup_dir, resource)
33-
34-
resources = resource_function()
35-
print('Backing up {0} {1}'.format(str(len(resources)), resource))
36-
37-
if not os.path.exists(backup_dir):
38-
os.makedirs(backup_dir)
39-
40-
for resource_item in resources:
41-
item = None
42-
if 'id' in resource_item:
43-
resource_id = resource_item.get('id')
44-
try:
45-
item = self.foreman.get_resource(resource_type=resource, resource_id=resource_id)
46-
except ForemanError as e:
47-
# There seems to be a bug in Foreman 1.7.3 whereas the API reports 404
48-
# while executing a get request on organizations/:id
49-
# API: http://theforeman.org/api/apidoc/v2/organizations/show.html
50-
if e.status_code == 404:
51-
item = resource_item
52-
53-
if item:
54-
if 'title' in item:
55-
file_name = item.get('title')
56-
elif 'login' in item:
57-
file_name = item.get('login')
58-
elif 'name' in item:
59-
file_name = item.get('name')
60-
else:
61-
print('Can\'t backup {0}'.format(item))
62-
continue
63-
backup_file = os.path.join(backup_dir, file_name.replace('/', '_') + '.yaml')
64-
with open(backup_file, 'w') as backup_file:
65-
yaml.safe_dump(item, backup_file, default_flow_style=False)
85+
backup_dir = os.path.join(self.backup_dir, type)
86+
ensure_dir(dir=backup_dir)
87+
88+
for resource in items:
89+
if 'title' in resource:
90+
file_name = resource.get('title')
91+
elif 'login' in resource:
92+
file_name = resource.get('login')
93+
elif 'name' in resource:
94+
file_name = resource.get('name')
95+
else:
96+
print('Can\'t backup {0}'.format(resource))
97+
continue
98+
backup_file_name = os.path.join(backup_dir, '{name}'.format(name=file_name.replace('/', '_') + '.yaml'))
99+
with open(backup_file_name, 'w') as backup_file:
100+
yaml.safe_dump(resource, backup_file, default_flow_style=False)
101+
102+
103+
def backup(self, resource_type, resource_function):
104+
resources = self.get_resources(type=resource_type, resource_function=resource_function)
105+
print('Backing up {count} {resource_type}'.format(count=str(len(resources)), resource_type=resource_type))
106+
self.write_resources(type=resource_type, items=resources, backup_dir=self.backup_dir)
66107

67108
def run(self):
68-
self.backup_foreman()
109+
ensure_dir(self.backup_dir)
110+
self.backup_resources()
69111
if self.katello_support:
70112
self.backup_katello()
71113

72-
def backup_foreman(self):
114+
def backup_resources(self):
73115

74-
self.backup(resource='architectures',
116+
self.backup(resource_type='architectures',
75117
resource_function=self.foreman.get_architectures)
76-
self.backup(resource='common_parameters',
118+
self.backup(resource_type='common_parameters',
77119
resource_function=self.foreman.get_common_parameters)
78-
self.backup(resource='compute_resources',
120+
self.backup(resource_type='compute_resources',
79121
resource_function=self.foreman.get_compute_resources)
80-
self.backup(resource='compute_profiles',
122+
self.backup(resource_type='compute_profiles',
81123
resource_function=self.foreman.get_compute_profiles)
82-
self.backup(resource='config_templates',
124+
self.backup(resource_type='config_templates',
83125
resource_function=self.foreman.get_config_templates)
84-
self.backup(resource='domains',
126+
self.backup(resource_type='domains',
85127
resource_function=self.foreman.get_domains)
86-
self.backup(resource='environments',
128+
self.backup(resource_type='environments',
87129
resource_function=self.foreman.get_environments)
88-
self.backup(resource='hosts',
130+
self.backup(resource_type='hosts',
89131
resource_function=self.foreman.get_hosts)
90-
self.backup(resource='hostgroups',
132+
self.backup(resource_type='hostgroups',
91133
resource_function=self.foreman.get_hostgroups)
92-
self.backup(resource='media',
134+
self.backup(resource_type='media',
93135
resource_function=self.foreman.get_media)
94-
self.backup(resource='operatingsystems',
136+
self.backup(resource_type='operatingsystems',
95137
resource_function=self.foreman.get_operatingsystems)
96-
self.backup(resource='roles',
138+
self.backup(resource_type='roles',
97139
resource_function=self.foreman.get_roles)
98-
self.backup(resource='smart_proxies',
140+
self.backup(resource_type='smart_proxies',
99141
resource_function=self.foreman.get_smart_proxies)
100-
self.backup(resource='subnets',
142+
self.backup(resource_type='subnets',
101143
resource_function=self.foreman.get_subnets)
102-
self.backup(resource='users',
144+
self.backup(resource_type='users',
103145
resource_function=self.foreman.get_users)
104146

105147

106148
def backup_katello(self):
107-
self.backup(resource='locations',
149+
self.backup(resource_type='locations',
108150
resource_function=self.foreman.get_locations)
109-
self.backup(resource='organizations',
151+
self.backup(resource_type='organizations',
110152
resource_function=self.foreman.get_organizations)
111153

112154

155+
class AnsibleBackup(ForemanBackup):
156+
invalid_keys = ['created_at', 'updated_at', 'id']
157+
158+
def __init__(self, **kwargs):
159+
ForemanBackup.__init__(self, **kwargs)
160+
161+
162+
def write_resources(self, type, items, backup_dir):
163+
backup_file_name = os.path.join(backup_dir, type)
164+
resources = list()
165+
for i in range(len(items)):
166+
item = self.get_resource(type=type, id=items[i].get('id'))
167+
item = clear_data(item, invalid_keys=self.invalid_keys)
168+
item['state'] = 'present'
169+
resources.append(item)
170+
171+
with open(backup_file_name, 'w') as f:
172+
f.write('---\n')
173+
f.write('foreman_{resource}:'.format(resource=type))
174+
if len(resources) > 0:
175+
f.write('\n')
176+
else:
177+
f.write(' ')
178+
with open(backup_file_name, 'a') as f:
179+
yaml.safe_dump(resources, f, default_flow_style=False)
180+
181+
113182
def show_help():
114183
"""Print on screen how to use this script.
115184
"""
@@ -133,11 +202,13 @@ def main(argv):
133202
foreman_port = os.environ.get('FOREMAN_PORT', '443')
134203
foreman_user = os.environ.get('FOREMAN_USER', 'foreman')
135204
foreman_pass = os.environ.get('FOREMAN_PASS', 'changme')
136-
katello_support = string2bool(os.environ.get('FOREMAN_KATELLO_SUPPORT', 'False'))
205+
ansible_format = os.environ.get('FOREMAN_BACKUP_ANSIBLE_FORMAT', False)
206+
backup_dir = os.environ.get('FOREMAN_BACKUP_DIR', '.')
207+
katello_support = string2bool(os.environ.get('FOREMAN_KATELLO_SUPPORT', False))
137208

138209
try:
139210
opts, args = getopt.getopt(argv,
140-
"f:hu:p:s:k",
211+
"ab:f:hu:p:s:k",
141212
["foreman=", "username=", "port=", "secret="])
142213
except getopt.GetoptError:
143214
show_help()
@@ -150,16 +221,28 @@ def main(argv):
150221
sys.exit()
151222
elif opt == '-k':
152223
katello_support = True
224+
elif opt == '-a':
225+
ansible_format = True
226+
elif opt == '-b':
227+
backup_dir = arg
153228
elif opt in ('-u', '--username'):
154229
foreman_username = arg
155230
elif opt in ('-p', '--port'):
156231
foreman_port = arg
157232
elif opt in ('-s', '--secret'):
158233
foreman_password = arg
159234

160-
backup = ForemanBackup(foreman_host, foreman_port,
161-
foreman_user, foreman_pass,
162-
katello_support)
235+
if ansible_format:
236+
backup_class = AnsibleBackup
237+
else:
238+
backup_class = ForemanBackup
239+
240+
backup = backup_class(hostname=foreman_host,
241+
port=foreman_port,
242+
username=foreman_user,
243+
password=foreman_pass,
244+
katello_support=katello_support,
245+
backup_dir=backup_dir)
163246
backup.run()
164247

165248

0 commit comments

Comments
 (0)