├── .gitignore
├── README.md
├── __init__.py
├── foreman_architecture.py
├── foreman_compute_attribute.py
├── foreman_compute_profile.py
├── foreman_compute_resource.py
├── foreman_config_template.py
├── foreman_domain.py
├── foreman_environment.py
├── foreman_external_usergroup.py
├── foreman_filter.py
├── foreman_global_parameter.py
├── foreman_host.py
├── foreman_host_check.py
├── foreman_hostgroup.py
├── foreman_image.py
├── foreman_ldap.py
├── foreman_location.py
├── foreman_medium.py
├── foreman_operatingsystem.py
├── foreman_organization.py
├── foreman_os_default_template.py
├── foreman_ptable.py
├── foreman_realm.py
├── foreman_role.py
├── foreman_setting.py
├── foreman_smart_proxy.py
├── foreman_subnet.py
├── foreman_user.py
├── foreman_usergroup.py
└── module_utils
└── foreman_utils.py
/.gitignore:
--------------------------------------------------------------------------------
1 | *.pyc
2 | .idea
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Ansible library Foreman
2 | ==========
3 |
4 | # Table of Contents
5 | - [Description](#description)
6 | - [Requirements](#requirements)
7 | - [Examples](#examples)
8 | - [License](#license)
9 | - [Author information](#author information)
10 |
11 | # Description
12 | Ansible library to configure [Foreman] and manage hosts.
13 |
14 | With the current implementation it's possible to create, update and delete the following Foreman Resources
15 | - Architectures
16 | - Compute Attributes
17 | - Compute Profiles
18 | - Compute Resources
19 | - Config Templates
20 | - Domains
21 | - Environments
22 | - Hosts
23 | - Hostgroups
24 | - Locations (needs Katello)
25 | - Medium
26 | - Operatingsystems
27 | - Operatingsystem default templates
28 | - Organizations (need s Katello)
29 | - Partition Tables
30 | - Roles
31 | - Smart Proxies
32 | - Subnets
33 | - Users
34 |
35 | # Requirements
36 | [python-foreman] >= 0.12.11 is required to be installed on the system where Ansible is started from.
37 |
38 | # Examples
39 | `ansible.cfg` has to contain path to modules and module_utils:
40 | ```
41 | [default]
42 | library = ansible-module-foreman
43 | module_utils = ansible-module-foreman/module_utils
44 | ```
45 | The following parameters are always required so the module knows how to connect to the Foreman [API v2].
46 | They are replaced in the examples by three dots (...).
47 |
48 | ```yaml
49 | foreman_host: foreman.example.com
50 | foreman_port: 443
51 | foreman_user: admin
52 | foreman_pass: password
53 | ```
54 |
55 | ## Architecture
56 | ```yaml
57 | - name: Ensure Architecture
58 | foreman_architecture:
59 | name: x86_64
60 | state: present
61 | foreman_host: foreman.example.com
62 | foreman_port: 443
63 | foreman_user: admin
64 | foreman_pass: password
65 | ```
66 |
67 | ## Compute Profile
68 | ```yaml
69 | - name: Ensure Compute Profile
70 | foreman_compute_profile:
71 | name: 1-Small
72 | foreman_host: foreman.example.com
73 | foreman_port: 443
74 | foreman_user: admin
75 | foreman_pass: password
76 | ```
77 |
78 | ## Compute Resource
79 | ```yaml
80 | - name: Ensure Compute Resource
81 | foreman_compute_resource:
82 | name: VMwareCluster01
83 | state: present
84 | url: vsphere.example.com
85 | provider: VMWare
86 | user: ansible
87 | password: secret
88 | server: vsphere.example.com
89 | ...
90 | ```
91 |
92 | ## Compute Attribute
93 | This is an example to configure VMware vSphere attributes.
94 | ```yaml
95 | - name: Ensure Compute Attribute
96 | foreman_compute_attribute:
97 | compute_profile: 1-Small
98 | compute_resource: VMwareCluster1
99 | vm_attributes:
100 | cluster: Cluster1
101 | corespersocket: 1
102 | cpus: 1
103 | guest_id: otherGuest64
104 | hardware_version: vmx-10
105 | interfaces_attributes:
106 | '0':
107 | _delete: ''
108 | network: network-40
109 | type: VirtualVmxnet3
110 | '1':
111 | _delete: ''
112 | network: network-40
113 | type: VirtualVmxnet3
114 | new_interfaces:
115 | _delete: ''
116 | network: network-40
117 | type: VirtualVmxnet3
118 | memory_mb: 1024
119 | path: /Datacenters/DC01/vm/example
120 | scsi_controller_type: ParaVirtualSCSIController
121 | volumes_attributes:
122 | '0':
123 | _delete: ''
124 | datastore: DS01
125 | eager_zero: true
126 | name: Hard disk
127 | size_gb: 16
128 | thin: true
129 | new_volumes:
130 | _delete: ''
131 | datastore: DS01
132 | eager_zero: true
133 | name: Hard disk
134 | size_gb: 16
135 | thin: true
136 | ...
137 | ```
138 |
139 | ## Config Template
140 | ### Deploy existing file
141 | ```yaml
142 | - name: Ensure Config Template
143 | foreman_config_template:
144 | name: CoreOS Cloud-config
145 | locked: false
146 | operatingsystems:
147 | - CoreOS
148 | template_file: files/coreos-cloud-config
149 | snippet: true
150 | state: present
151 | ...
152 | ```
153 | ### Deploy content
154 | ```yaml
155 | - name: Ensure Config Template
156 | foreman_config_template:
157 | name: CoreOS Cloud-config
158 | locked: false
159 | operatingsystems:
160 | - CoreOS
161 | template: "Some content"
162 | snippet: true
163 | state: present
164 | ...
165 | ```
166 |
167 | ## Domain
168 | ```yaml
169 | - name: Ensure Domain
170 | foreman_domain:
171 | name: example.com
172 | state: present
173 | ...
174 | ```
175 |
176 | ## Environments
177 | ```yaml
178 | - name: Ensure Environment
179 | foreman_environment:
180 | name: Production
181 | state: present
182 | ...
183 | ```
184 | ## Host
185 | ### Provision using installation from medium
186 | ```yaml
187 | - name: Ensure Host
188 | foreman_host:
189 | name: ansible-host-01
190 | state: running
191 | architecture: x86_64
192 | domain: example.com
193 | environment: production
194 | medium: CoreOS
195 | provision_method: build
196 | root_pass: topsecret
197 | ```
198 |
199 | ### Provision by clone from image
200 | ```yaml
201 | - name: Ensure Host
202 | foreman_host:
203 | name: ansible-host-03
204 | state: running
205 | compute_resource: VMwareCluster01
206 | hostgroup: Hostgroup01
207 | image: CoreOS Image
208 | provision_method: image
209 | ...
210 | ```
211 | ### Provision using a hostgroup
212 | ```yaml
213 | - name: Ensure Host
214 | foreman_host:
215 | name: ansible-host-02
216 | state: running
217 | compute_resource: VMwareCluster01
218 | hostgroup: Hostgroup01
219 | provision_method: build
220 | ...
221 | ```
222 | ### Delete host
223 | To delete a host Foreman must know the FQDN. Use one of the following methods:
224 | ```yaml
225 | - name: Ensure absent host
226 | foreman_host:
227 | name: ansible-host-01
228 | domain: example.com
229 | state: absent
230 | ...
231 | ```
232 | or
233 | ```yaml
234 | - name: Ensure absent host
235 | foreman_host:
236 | name: ansible-host-01.example.com
237 | state: absent
238 | ...
239 | ```
240 | ### Host with network interfaces
241 | ```yaml
242 | - name: Ensure Host
243 | foreman_host:
244 | name: ansible-host-04
245 | state: present
246 | .
247 | .
248 | interfaces:
249 | - ip: 10.11.12.123
250 | mac: 00:21:f6:16:e4:2e
251 | subnet: "Dev Network"
252 | - ip: 10.11.12.124
253 | mac: 00:21:f6:42:52:91
254 | subnet: "Dev Network"
255 | ...
256 | ```
257 | ## Hostgroup
258 | ```yaml
259 | - name: Ensure Hostgroup
260 | foreman_hostgroup:
261 | name: Hostgroup01
262 | architecture: x86_64
263 | domain: example.com
264 | environment: production
265 | medium: CoreOS mirror
266 | operatingsystem: CoreOS
267 | partition_table: CoreOS Partition Table
268 | subnet: example.com
269 | state: present
270 | ...
271 | ```
272 |
273 | ## Location
274 | ```
275 | - name: Ensure Location
276 | foreman_location:
277 | name: Location01
278 | state: present
279 | ...
280 | ```
281 |
282 | ## Medium
283 | ```yaml
284 | - name: Ensure Medium
285 | foreman_medium:
286 | name: CoreOS
287 | path: http://$release.release.core-os.net
288 | os_family: CoreOS
289 | state: present
290 | ...
291 | ```
292 |
293 | ## Operatingsystem
294 | ```yaml
295 | - name: Ensure Operatingsystem
296 | foreman_operatingsystem:
297 | name: CoreOS
298 | major: 633
299 | minor: 0.0
300 | architectures:
301 | - x86_64
302 | media:
303 | - CoreOS mirror
304 | ptables:
305 | - CoreOS default fake
306 | state: present
307 | ...
308 | ```
309 |
310 | ## Operatingsystem default template
311 | ```yaml
312 | - name: Ensure Operatingsystem default template
313 | foreman_os_default_template:
314 | operatingsystem: CoreOS
315 | config_template: CoreOS PXELinux
316 | template_kind: PXELinux
317 | state: present
318 | ...
319 | ```
320 |
321 | ## Organization
322 | Works only if Katello is used
323 | ```yaml
324 | - name: Ensure Organization
325 | foreman_organization:
326 | name: MyOrganization
327 | state: present
328 | ...
329 | ```
330 |
331 | ## Partition Table
332 | ```yaml
333 | - name: Ensure partition table
334 | foreman_ptable:
335 | name: MyPartitionTable
336 | layout: 'some layout'
337 | os_family: CoreOS
338 | state: present
339 | ...
340 | ```
341 | ## Role
342 | ```yaml
343 | - name: Ensure Role
344 | foreman_role:
345 | name: MyRole
346 | state: present
347 | ```
348 |
349 | ## Smart Proxy
350 | ```yaml
351 | - name: Ensure Smart Proxy
352 | foreman_smart_proxy:
353 | name: SmartProxy01
354 | url: http://localhost:8443
355 | state: present
356 | ...
357 | ```
358 |
359 | ## User
360 | ```yaml
361 | - name: Ensure User
362 | foreman_user:
363 | login: MyUser
364 | admin: false
365 | auth: 'Internal'
366 | firstname: Testing
367 | lastname: User
368 | mail: testing.user@example.com
369 | password: topsecret
370 | roles:
371 | - Manager
372 | - Viewer
373 | state: present
374 | ```
375 |
376 | # License
377 |
378 | Copyright 2015 Thomas Krahn
379 |
380 | Licensed under the Apache License, Version 2.0 (the "License");
381 | you may not use this file except in compliance with the License.
382 | You may obtain a copy of the License at
383 |
384 | http://www.apache.org/licenses/LICENSE-2.0
385 |
386 | Unless required by applicable law or agreed to in writing, software
387 | distributed under the License is distributed on an "AS IS" BASIS,
388 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
389 | See the License for the specific language governing permissions and
390 | limitations under the License.
391 |
392 | # Author
393 |
394 | [Thomas Krahn]
395 |
396 | [Foreman]: www.theforeman.org
397 | [API v2]: www.theforeman.org/api_v2.html
398 | [python-foreman]: https://github.com/Nosmoht/python-foreman
399 | [Thomas Krahn]: mailto:ntbc@gmx.net
400 |
--------------------------------------------------------------------------------
/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nosmoht/ansible-module-foreman/d5509cc74025c842fb1c63aae4e1d36c31ce026d/__init__.py
--------------------------------------------------------------------------------
/foreman_architecture.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding: utf-8 -*-
3 | #
4 | # Ansible module to manage Foreman architecture resources.
5 | #
6 | # This module is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This software is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with this software. If not, see .
18 |
19 | DOCUMENTATION = '''
20 | ---
21 | module: foreman_architecture
22 | short_description: Manage Foreman Architectures using Foreman API v2
23 | description:
24 | - Create and delete Foreman Architectures using Foreman API v2
25 | options:
26 | name:
27 | description: Name of architecture
28 | required: true
29 | aliases: []
30 | state:
31 | description: State of architecture
32 | required: false
33 | default: present
34 | choices: ["present", "absent"]
35 | foreman_host:
36 | description: Hostname or IP address of Foreman system
37 | required: false
38 | default: 127.0.0.1
39 | foreman_port:
40 | description: Port of Foreman API
41 | required: false
42 | default: 443
43 | foreman_user:
44 | description: Username to be used to authenticate on Foreman
45 | required: true
46 | foreman_pass:
47 | description: Password to be used to authenticate user on Foreman
48 | required: true
49 | foreman_ssl:
50 | description: Enable SSL when connecting to Foreman API
51 | required: false
52 | default: true
53 | requires:
54 | - python-foreman > 0.14.0
55 | author: "Thomas Krahn (@nosmoht)"
56 | '''
57 |
58 | EXAMPLES = '''
59 | - name: Ensure ARM Architecture is present
60 | foreman_architecture:
61 | name: ARM
62 | state: present
63 | foreman_user: admin
64 | foreman_pass: secret
65 | foreman_host: foreman.example.com
66 | foreman_port: 443
67 | '''
68 |
69 | try:
70 | from foreman.foreman import *
71 | except ImportError:
72 | foremanclient_found = False
73 | else:
74 | foremanclient_found = True
75 |
76 |
77 | def ensure(module, theforeman):
78 | name = module.params['name']
79 | state = module.params['state']
80 |
81 | data = dict(name=name)
82 |
83 | try:
84 | arch = theforeman.search_architecture(data=data)
85 | except ForemanError as e:
86 | module.fail_json(msg='Could not get architecture: {0}'.format(e.message))
87 |
88 | if not arch and state == 'present':
89 | try:
90 | arch = theforeman.create_architecture(data)
91 | except ForemanError as e:
92 | module.fail_json(msg='Could not create architecture: {0}'.format(e.message))
93 | return True, arch
94 |
95 | if arch and state == 'absent':
96 | try:
97 | arch = theforeman.delete_architecture(id=arch.get('id'))
98 | except ForemanError as e:
99 | module.fail_json(msg='Could not delete architecture: {0}'.format(e.message))
100 | return True, arch
101 |
102 | return False, arch
103 |
104 |
105 | def main():
106 | module = AnsibleModule(
107 | argument_spec=dict(
108 | name=dict(type='str', required=True),
109 | state=dict(type='str', default='present', choices=['present', 'absent']),
110 | foreman_host=dict(type='str', default='127.0.0.1'),
111 | foreman_port=dict(type='str', default='443'),
112 | foreman_user=dict(type='str', required=True),
113 | foreman_pass=dict(type='str', required=True, no_log=True),
114 | foreman_ssl=dict(type='bool', default=True)
115 | ),
116 | )
117 |
118 | if not foremanclient_found:
119 | module.fail_json(msg='python-foreman module is required. See https://github.com/Nosmoht/python-foreman.')
120 |
121 | foreman_host = module.params['foreman_host']
122 | foreman_port = module.params['foreman_port']
123 | foreman_user = module.params['foreman_user']
124 | foreman_pass = module.params['foreman_pass']
125 | foreman_ssl = module.params['foreman_ssl']
126 |
127 | theforeman = Foreman(hostname=foreman_host,
128 | port=foreman_port,
129 | username=foreman_user,
130 | password=foreman_pass,
131 | ssl=foreman_ssl)
132 |
133 | changed, arch = ensure(module, theforeman)
134 | module.exit_json(changed=changed, architecture=arch)
135 |
136 |
137 | from ansible.module_utils.basic import *
138 |
139 | if __name__ == '__main__':
140 | main()
141 |
--------------------------------------------------------------------------------
/foreman_compute_attribute.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding: utf-8 -*-
3 | #
4 | # Ansible module to manage Foreman compute attribute resources.
5 | #
6 | # This module is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This software is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with this software. If not, see .
18 |
19 | DOCUMENTATION = '''
20 | ---
21 | module: foreman_compute_attribute
22 | short_description: Manage Foreman Compute Attributes using Foreman API v2
23 | description:
24 | - Create and update Foreman Compute Attributes using Foreman API v2
25 | options:
26 | compute_resource:
27 | description: Name of compute resource
28 | required: true
29 | compute_profile:
30 | description: Name of compute profile
31 | required: true
32 | vm_attributes:
33 | description: Hash containing the data of vm_attrs
34 | required: true
35 | foreman_host:
36 | description: Hostname or IP address of Foreman system
37 | required: false
38 | default: 127.0.0.1
39 | foreman_port:
40 | description: Port of Foreman API
41 | required: false
42 | default: 443
43 | foreman_user:
44 | description: Username to be used to authenticate on Foreman
45 | required: true
46 | foreman_pass:
47 | description: Password to be used to authenticate user on Foreman
48 | required: true
49 | foreman_ssl:
50 | description: Enable SSL when connecting to Foreman API
51 | required: false
52 | default: true
53 | notes:
54 | - Requires the python-foreman package to be installed. See https://github.com/Nosmoht/python-foreman.
55 | version_added: "2.0"
56 | author: "Thomas Krahn (@nosmoht)"
57 | '''
58 |
59 | try:
60 | from foreman.foreman import *
61 |
62 | foremanclient_found = True
63 | except ImportError:
64 | foremanclient_found = False
65 |
66 |
67 | def ensure(module):
68 | compute_profile_name = module.params['compute_profile']
69 | compute_resource_name = module.params['compute_resource']
70 | vm_attributes = module.params['vm_attributes']
71 |
72 | foreman_host = module.params['foreman_host']
73 | foreman_port = module.params['foreman_port']
74 | foreman_user = module.params['foreman_user']
75 | foreman_pass = module.params['foreman_pass']
76 | foreman_ssl = module.params['foreman_ssl']
77 |
78 | theforeman = Foreman(hostname=foreman_host,
79 | port=foreman_port,
80 | username=foreman_user,
81 | password=foreman_pass,
82 | ssl=foreman_ssl)
83 |
84 | try:
85 | compute_resource = theforeman.search_compute_resource(data={'name': compute_resource_name})
86 | if not compute_resource:
87 | module.fail_json(msg='Compute resource not found: {0}'.format(compute_resource_name))
88 | except ForemanError as e:
89 | module.fail_json(msg='Could not get compute resource: {0}'.format(compute_resource_name))
90 |
91 | try:
92 | compute_profile = theforeman.search_compute_profile(data={'name': compute_profile_name})
93 | if not compute_profile:
94 | module.fail_json(msg='Compute profile {0} not found on {1}'.format(compute_profile_name,
95 | compute_resource_name))
96 | except ForemanError as e:
97 | module.fail_json(msg='Could not get compute profile {0} on {1}'.format(compute_profile_name,
98 | compute_resource_name))
99 |
100 | compute_attributes = theforeman.get_compute_attribute(compute_resource_id=compute_resource.get('id'),
101 | compute_profile_id=compute_profile.get('id'))
102 |
103 | if compute_attributes:
104 | try:
105 | # Python 2
106 | compute_attribute = compute_attributes[0]
107 | except TypeError:
108 | # Python 3
109 | compute_attribute = next(compute_attributes)
110 | else:
111 | compute_attribute = None
112 |
113 | if not compute_attribute:
114 | try:
115 | compute_attribute = theforeman.create_compute_attribute(compute_resource_id=compute_resource.get('id'),
116 | compute_profile_id=compute_profile.get('id'),
117 | data={'vm_attrs': vm_attributes})
118 | return True, compute_attribute
119 | except ForemanError as e:
120 | module.fail_json(msg='Could not create compute attribute: {0}'.format(e.message))
121 |
122 | if not all(compute_attribute['vm_attrs'].get(key, vm_attributes.get(key)) == vm_attributes.get(key) for key in
123 | vm_attributes) != 0:
124 | try:
125 | compute_attribute = theforeman.update_compute_attribute(id=compute_attribute.get('id'),
126 | data=vm_attributes)
127 | return True, compute_attribute
128 | except ForemanError as e:
129 | module.fail_json(msg='Could not update compute attribute: {0}'.format(e.message))
130 |
131 | return False, compute_attribute
132 |
133 |
134 | def main():
135 | module = AnsibleModule(
136 | argument_spec=dict(
137 | compute_profile=dict(type='str', required=True),
138 | compute_resource=dict(type='str', required=True),
139 | vm_attributes=dict(type='dict', required=False),
140 | foreman_host=dict(type='str', Default='127.0.0.1'),
141 | foreman_port=dict(type='str', Default='443'),
142 | foreman_user=dict(type='str', required=True),
143 | foreman_pass=dict(type='str', required=True, no_log=True),
144 | foreman_ssl=dict(type='bool', required=False, default=True)
145 | ),
146 | )
147 |
148 | if not foremanclient_found:
149 | module.fail_json(msg='python-foreman is required. See https://github.com/Nosmoht/python-foreman.')
150 |
151 | changed, compute_attribute = ensure(module)
152 | module.exit_json(changed=changed, compute_attribute=compute_attribute)
153 |
154 |
155 | from ansible.module_utils.basic import *
156 |
157 | if __name__ == '__main__':
158 | main()
159 |
--------------------------------------------------------------------------------
/foreman_compute_profile.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding: utf-8 -*-
3 | #
4 | # Ansible module to manage Foreman compute profile resources.
5 | #
6 | # This module is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This software is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with this software. If not, see .
18 |
19 | DOCUMENTATION = '''
20 | ---
21 | module: foreman_compute_profile
22 | short_description: Manage Foreman Compute Profiles using Foreman API v2
23 | description:
24 | - Create and delete Foreman Compute Profiles using Foreman API v2
25 | options:
26 | name:
27 | description: Name of Compute Profile
28 | required: true
29 | state:
30 | description: State of Compute Profile
31 | required: false
32 | default: present
33 | choices: ["present", "absent"]
34 | foreman_host:
35 | description: Hostname or IP address of Foreman
36 | required: false
37 | default: 127.0.0.1
38 | foreman_port:
39 | description: Port of Foreman API
40 | required: false
41 | default: 443
42 | foreman_user:
43 | description: Username to be used to authenticate on Foreman
44 | required: true
45 | foreman_pass:
46 | description: Password to be used to authenticate user on Foreman
47 | required: true
48 | foreman_ssl:
49 | description: Enable SSL when connecting to Foreman API
50 | required: false
51 | default: true
52 | notes:
53 | - Requires the python-foreman package to be installed. See https://github.com/Nosmoht/python-foreman.
54 | version_added: "2.0"
55 | author: "Thomas Krahn (@nosmoht)"
56 | '''
57 |
58 | EXAMPLES = '''
59 | - name: Ensure Extra Large Compute Profile is present
60 | foreman_compute_profile:
61 | name: 4-Extra-Large
62 | state: present
63 | foreman_user: admin
64 | foreman_pass: secret
65 | '''
66 |
67 | try:
68 | from foreman.foreman import *
69 | except ImportError:
70 | foremanclient_found = False
71 | else:
72 | foremanclient_found = True
73 |
74 |
75 | def ensure(module):
76 | name = module.params['name']
77 | state = module.params['state']
78 |
79 | foreman_host = module.params['foreman_host']
80 | foreman_port = module.params['foreman_port']
81 | foreman_user = module.params['foreman_user']
82 | foreman_pass = module.params['foreman_pass']
83 | foreman_ssl = module.params['foreman_ssl']
84 |
85 | theforeman = Foreman(hostname=foreman_host,
86 | port=foreman_port,
87 | username=foreman_user,
88 | password=foreman_pass,
89 | ssl=foreman_ssl)
90 |
91 | data = dict(name=name)
92 |
93 | try:
94 | compute_profile = theforeman.search_compute_profile(data=data)
95 | except ForemanError as e:
96 | module.fail_json(msg='Could not get compute profile: {0}'.format(e.message))
97 |
98 | if state == 'absent':
99 | if compute_profile:
100 | try:
101 | compute_profile = theforeman.delete_compute_profile(id=compute_profile.get('id'))
102 | except ForemanError as e:
103 | module.fail_json(msg='Could not delete compute profile: {0}'.format(e.message))
104 | return True, compute_profile
105 | return False, compute_profile
106 |
107 | if state == 'present':
108 | if not compute_profile:
109 | try:
110 | compute_profile = theforeman.create_compute_profile(data=data)
111 | except ForemanError as e:
112 | module.fail_json(msg='Could not create compute profile: {0}'.format(e.message))
113 | return True, compute_profile
114 |
115 | return False, compute_profile
116 |
117 |
118 | def main():
119 | module = AnsibleModule(
120 | argument_spec=dict(
121 | name=dict(type='str', required=True),
122 | state=dict(type='str', default='present', choices=['present', 'absent']),
123 | foreman_host=dict(type='str', default='127.0.0.1'),
124 | foreman_port=dict(type='str', default='443'),
125 | foreman_user=dict(type='str', required=True),
126 | foreman_pass=dict(type='str', required=True, no_log=True),
127 | foreman_ssl=dict(type='bool', default=True)
128 | ),
129 | )
130 |
131 | if not foremanclient_found:
132 | module.fail_json(msg='python-foreman module is required. See https://github.com/Nosmoht/python-foreman.')
133 |
134 | changed, compute_profile = ensure(module)
135 | module.exit_json(changed=changed, compute_profile=compute_profile)
136 |
137 |
138 | from ansible.module_utils.basic import *
139 |
140 | if __name__ == '__main__':
141 | main()
142 |
--------------------------------------------------------------------------------
/foreman_compute_resource.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding: utf-8 -*-
3 | #
4 | # Ansible module to manage Foreman compute resource resources.
5 | #
6 | # This module is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This software is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with this software. If not, see .
18 |
19 | DOCUMENTATION = '''
20 | ---
21 | module: foreman_compute_resource
22 | short_description: Manage Foreman Compute resources using Foreman API v2
23 | description:
24 | - Create and delete Foreman Compute Resources using Foreman API v2
25 | options:
26 | name:
27 | description: Compute Resource name
28 | required: true
29 | datacenter: Name of Datacenter (only for Vmware)
30 | required: false
31 | default: None
32 | description: Description of compute resource
33 | required: false
34 | default: None
35 | locations: List of locations the compute resource should be assigned to
36 | required: false
37 | default: None
38 | organizations: List of organizations the compute resource should be assigned to
39 | required: false
40 | default: None
41 | password:
42 | description: Password for Ovirt, EC2, Vmware, Openstack. Secret key for EC2
43 | required: false
44 | default: None
45 | provider:
46 | description: Providers name (e.g. Ovirt, EC2, Vmware, Openstack, EC2, Google)
47 | required: false
48 | default: None
49 | server:
50 | description: Hostname of Vmware vSphere system
51 | required: false
52 | default: None
53 | state:
54 | description: Compute Resource state
55 | required: false
56 | default: present
57 | choices: ["present", "absent"]
58 | tenant:
59 | description: Tenant name for Openstack
60 | required: false
61 | default: None
62 | domain:
63 | description: Domain name for Openstack (required for Keystone v3 API)
64 | required: false
65 | default: Default
66 | url:
67 | description: URL for Libvirt, Ovirt, and Openstack
68 | required: false
69 | default: None
70 | user:
71 | description: Username for Ovirt, EC2, Vmware, Openstack. Access Key for EC2.
72 | required: false
73 | default: None
74 | foreman_host:
75 | description: Hostname or IP address of Foreman system
76 | required: false
77 | default: 127.0.0.1
78 | foreman_port:
79 | description: Port of Foreman API
80 | required: false
81 | default: 443
82 | foreman_user:
83 | description: Username to be used to authenticate on Foreman
84 | required: true
85 | foreman_pass:
86 | description: Password to be used to authenticate user on Foreman
87 | required: true
88 | foreman_ssl:
89 | description: Enable SSL when connecting to Foreman API
90 | required: false
91 | default: true
92 | notes:
93 | - Requires the python-foreman package to be installed. See https://github.com/Nosmoht/python-foreman.
94 | version_added: "2.0"
95 | author: "Thomas Krahn (@nosmoht)"
96 | '''
97 |
98 | EXAMPLES = '''
99 | - name: Ensure Vmware compute resource
100 | foreman_compute_resource:
101 | name: VMware
102 | datacenter: dc01
103 | locations:
104 | - Nevada
105 | organizations:
106 | - DevOps
107 | provider: VMware
108 | server: vsphere.example.com
109 | url: vsphere.example.com
110 | user: domain\admin
111 | password: secret
112 | state: present
113 | foreman_user: admin
114 | foreman_pass: secret
115 | - name: Ensure Openstack compute resource
116 | foreman_compute_resource:
117 | name: Openstack
118 | provider: OpenStack
119 | tenant: ExampleTenant
120 | url: https://compute01.example.com:5000/v2.0/tokens
121 | user: admin
122 | '''
123 |
124 | try:
125 | from foreman.foreman import *
126 | except ImportError:
127 | foremanclient_found = False
128 | else:
129 | foremanclient_found = True
130 |
131 |
132 | def get_provider_params(provider):
133 | provider_name = provider.lower()
134 |
135 | if provider_name == 'docker':
136 | return ['password', 'url', 'user']
137 | elif provider_name == 'ec2':
138 | return ['access_key', 'password', 'region', 'url', 'user']
139 | elif provider_name == 'google':
140 | return ['email', 'key_path', 'project', 'url', 'zone']
141 | elif provider_name == 'libvirt':
142 | return ['display_type', 'url']
143 | elif provider_name == 'ovirt':
144 | return ['url', 'user', 'password']
145 | elif provider_name == 'openstack':
146 | return ['url', 'user', 'password', 'tenant', 'domain']
147 | elif provider_name == 'vmware':
148 | return ['datacenter', 'user', 'password', 'server']
149 | else:
150 | return []
151 |
152 | def get_organization_ids(module, theforeman, organizations):
153 | result = []
154 | for i in range(0, len(organizations)):
155 | try:
156 | organization = theforeman.search_organization(data={'name': organizations[i]})
157 | if not organization:
158 | module.fail_json('Could not find Organization {0}'.format(organizations[i]))
159 | result.append(organization.get('id'))
160 | except ForemanError as e:
161 | module.fail_json('Could not get Organizations: {0}'.format(e.message))
162 | return result
163 |
164 |
165 | def get_location_ids(module, theforeman, locations):
166 | result = []
167 | for i in range(0, len(locations)):
168 | try:
169 | location = theforeman.search_location(data={'name':locations[i]})
170 | if not location:
171 | module.fail_json('Could not find Location {0}'.format(locations[i]))
172 | result.append(location.get('id'))
173 | except ForemanError as e:
174 | module.fail_json('Could not get Locations: {0}'.format(e.message))
175 | return result
176 |
177 |
178 | def ensure(module):
179 | name = module.params['name']
180 | state = module.params['state']
181 | provider = module.params['provider']
182 | description = module.params['description']
183 | locations = module.params['locations']
184 | organizations = module.params['organizations']
185 |
186 | foreman_host = module.params['foreman_host']
187 | foreman_port = module.params['foreman_port']
188 | foreman_user = module.params['foreman_user']
189 | foreman_pass = module.params['foreman_pass']
190 | foreman_ssl = module.params['foreman_ssl']
191 |
192 | theforeman = Foreman(hostname=foreman_host,
193 | port=foreman_port,
194 | username=foreman_user,
195 | password=foreman_pass,
196 | ssl=foreman_ssl)
197 |
198 | data = dict(name=name)
199 |
200 |
201 | try:
202 | compute_resource = theforeman.search_compute_resource(data=data)
203 | except ForemanError as e:
204 | module.fail_json(msg='Could not get compute resource: {0}'.format(e.message))
205 |
206 | if organizations:
207 | data['organization_ids'] = get_organization_ids(module, theforeman, organizations)
208 |
209 | if locations:
210 | data['location_ids'] = get_location_ids(module, theforeman, locations)
211 |
212 | if state == 'absent':
213 | if compute_resource:
214 | try:
215 | compute_resource = theforeman.delete_compute_resource(id=compute_resource.get('id'))
216 | except ForemanError as e:
217 | module.fail_json(msg='Could not delete compute resource: {0}'.format(e.message))
218 | return True, compute_resource
219 |
220 | data['provider'] = provider
221 | params = get_provider_params(provider=provider) + ['description']
222 | for key in params:
223 | data[key] = module.params[key]
224 |
225 | if state == 'present':
226 | if not compute_resource:
227 | try:
228 | compute_resource = theforeman.create_compute_resource(data=data)
229 | except ForemanError as e:
230 | module.fail_json(msg='Could not create compute resource: {0}'.format(e.message))
231 | return True, compute_resource
232 |
233 | # Foreman's API doesn't return the password we can't tell if we need to
234 | # change it
235 | data['password'] = None
236 | if not all(data.get(key, None) == compute_resource.get(key, None) for key in params):
237 | try:
238 | compute_resource = theforeman.update_compute_resource(id=compute_resource.get('id'), data=data)
239 | except ForemanError as e:
240 | module.fail_json(msg='Could not update compute resource: {0}'.format(e.message))
241 | return True, compute_resource
242 |
243 | return False, compute_resource
244 |
245 |
246 | def main():
247 | module = AnsibleModule(
248 | argument_spec=dict(
249 | name=dict(type='str', required=True),
250 | access_key=dict(type='str', requireD=False),
251 | datacenter=dict(type='str', required=False),
252 | description=dict(type='str', required=False),
253 | display_type=dict(type='str', required=False),
254 | email=dict(type='str', required=False),
255 | key_path=dict(type='str', required=False),
256 | password=dict(type='str', required=False, no_log=True),
257 | provider=dict(type='str', required=False),
258 | region=dict(type='str', required=False),
259 | server=dict(type='str', required=False),
260 | url=dict(type='str', required=False),
261 | user=dict(type='str', required=False),
262 | state=dict(type='str', default='present', choices=['present', 'absent']),
263 | tenat=dict(type='str', required=False),
264 | domain=dict(type='str', required=False),
265 | locations=dict(type='list', required=False),
266 | organizations=dict(type='list', required=False),
267 | foreman_host=dict(type='str', default='127.0.0.1'),
268 | foreman_port=dict(type='str', default='443'),
269 | foreman_user=dict(type='str', required=True),
270 | foreman_pass=dict(type='str', required=True, no_log=True),
271 | foreman_ssl=dict(type='bool', default=True)
272 | ),
273 | )
274 |
275 | if not foremanclient_found:
276 | module.fail_json(msg='python-foreman module is required. See https://github.com/Nosmoht/python-foreman.')
277 |
278 | changed, compute_resource = ensure(module)
279 | module.exit_json(changed=changed, compute_resource=compute_resource)
280 |
281 |
282 | from ansible.module_utils.basic import *
283 |
284 | if __name__ == '__main__':
285 | main()
286 |
--------------------------------------------------------------------------------
/foreman_config_template.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding: utf-8 -*-
3 | #
4 | # Ansible module to manage Foreman config template resources.
5 | #
6 | # This module is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This software is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with this software. If not, see .
18 |
19 | DOCUMENTATION = '''
20 | ---
21 | module: foreman_config_template
22 | short_description:
23 | - Manage Foreman Provision Templates using Foreman API v2.
24 | description:
25 | - Create, update and and delete Foreman provision templates using Foreman API v2
26 | options:
27 | audit_comment:
28 | description:
29 | - Audit comment
30 | required: false
31 | default: None
32 | name:
33 | description: Provision template name
34 | required: true
35 | default: None
36 | locked:
37 | description: Whether or not the template is locked for editing
38 | required: false
39 | default: None
40 | operatingsystems:
41 | description: List of Operatingsystem names the template is assigned to
42 | required: false
43 | default: None
44 | template:
45 | description: RAW template content
46 | required: false
47 | default: None
48 | template_file:
49 | description: Path and filename to load the template from
50 | required: false
51 | default: None
52 | template_kind_name:
53 | description: Template Kind name
54 | required: false
55 | default: None
56 | snippet:
57 | description: Define if template is a snippet or not
58 | required: false
59 | default: None
60 | organizations:
61 | description:
62 | - List of organization the medium should be assigned to
63 | required: false
64 | locations:
65 | description:
66 | - List of locations the medium should be assigned to
67 | required: false
68 | state:
69 | description: Provision template state
70 | required: false
71 | default: 'present'
72 | choices: ['present', 'absent']
73 | foreman_host:
74 | description: Hostname or IP address of Foreman system
75 | required: false
76 | default: 127.0.0.1
77 | foreman_port:
78 | description: Port of Foreman API
79 | required: false
80 | default: 443
81 | foreman_user:
82 | description: Username to be used to authenticate on Foreman
83 | required: true
84 | foreman_pass:
85 | description: Password to be used to authenticate user on Foreman
86 | required: true
87 | foreman_ssl:
88 | description: Enable SSL when connecting to Foreman API
89 | required: false
90 | default: true
91 | notes:
92 | - Requires the python-foreman package to be installed. See https://github.com/Nosmoht/python-foreman.
93 | version_added: "2.0"
94 | author: "Thomas Krahn (@nosmoht)"
95 | '''
96 |
97 | EXAMPLES = '''
98 | - name: Ensure Config Template
99 | foreman_config_template:
100 | name: CoreOS Cloud-config
101 | locked: false
102 | operatingsystems:
103 | - CoreOS
104 | template_file: /tmp/coreos-cloud-config
105 | template_kind_name: provision
106 | snippet: true
107 | organizations:
108 | - Development
109 | - DevOps
110 | locations:
111 | - Prague
112 | state: present
113 | foreman_host: 127.0.0.1
114 | foreman_port: 443
115 | foreman_user: admin
116 | foreman_pass: secret
117 | '''
118 |
119 | try:
120 | from foreman.foreman import *
121 |
122 | foremanclient_found = True
123 | except ImportError:
124 | foremanclient_found = False
125 |
126 | try:
127 | from ansible.module_utils.foreman_utils import *
128 |
129 | has_import_error = False
130 | except ImportError as e:
131 | has_import_error = True
132 | import_error_msg = str(e)
133 |
134 |
135 | def templates_equal(data, config_template):
136 | comparable_keys = set(data.keys()).intersection(set(
137 | ['locked', 'snippet', 'template', 'audit_comment', 'template_kind_id']))
138 | if not all(data.get(key, None) == config_template.get(key, None) for key in comparable_keys):
139 | return False
140 | if not operatingsystems_equal(data, config_template):
141 | return False
142 | if not organizations_equal(data, config_template):
143 | return False
144 | if not locations_equal(data, config_template):
145 | return False
146 | return True
147 |
148 |
149 | def get_resources(resource_type, resource_func, resource_specs, search_field='name'):
150 | result = list()
151 | if not resource_specs:
152 | return result
153 | for item in resource_specs:
154 | search_data = dict()
155 | if isinstance(item, dict):
156 | for key in item:
157 | search_data[key] = item[key]
158 | else:
159 | search_data[search_field] = item
160 | try:
161 | resource = resource_func(data=search_data)
162 | if not resource:
163 | module.fail_json(
164 | msg='Could not find resource type {resource_type} specified as {name}'.format(
165 | resource_type=resource_type,
166 | name=item))
167 | result.append(resource)
168 | except ForemanError as e:
169 | module.fail_json(msg='Could not search resource type {resource_type} specified as {name}: {error}'.format(
170 | resource_type=resource_type, name=item, error=e.message))
171 | return result
172 |
173 |
174 | def ensure():
175 | audit_comment = module.params['audit_comment']
176 | locked = module.params['locked']
177 | name = module.params['name']
178 | operatingsystems = module.params['operatingsystems']
179 | state = module.params['state']
180 | snippet = module.params['snippet']
181 | template = module.params['template']
182 | template_file = module.params['template_file']
183 | template_kind_name = module.params['template_kind_name']
184 | organizations = module.params['organizations']
185 | locations = module.params['locations']
186 |
187 | theforeman = init_foreman_client(module)
188 |
189 | data = dict(name=name)
190 |
191 | try:
192 | config_template = theforeman.search_config_template(data=data)
193 | if config_template:
194 | config_template = theforeman.get_config_template(id=config_template.get('id'))
195 | except ForemanError as e:
196 | module.fail_json(msg='Could not get config template: {0}'.format(e.message))
197 |
198 | if state == 'absent':
199 | if config_template:
200 | try:
201 | config_template = theforeman.delete_config_template(id=config_template.get('id'))
202 | return True, config_template
203 | except ForemanError as e:
204 | module.fail_json(msg='Could not delete config template: {0}'.format(e.message))
205 |
206 | if state == 'present':
207 | if template and template_file:
208 | module.fail_json(msg='Only one of either template or template_file must be defined')
209 | if template:
210 | data['template'] = template
211 | elif template_file:
212 | try:
213 | with open(template_file) as f:
214 | data['template'] = f.read()
215 | except IOError as e:
216 | module.fail_json(msg='Could not open file {0}: {1}'.format(template_file, e.message))
217 |
218 | data['audit_comment'] = audit_comment
219 | if locked:
220 | data['locked'] = locked
221 | if snippet:
222 | data['snippet'] = snippet
223 |
224 | if organizations is not None:
225 | data['organization_ids'] = get_organization_ids(module, theforeman, organizations)
226 | if locations is not None:
227 | data['location_ids'] = get_location_ids(module, theforeman, locations)
228 | if operatingsystems is not None:
229 | data['operatingsystem_ids'] = get_operatingsystem_ids(module, theforeman, operatingsystems)
230 |
231 | if template_kind_name:
232 | res = get_resources(resource_type='template_kinds',
233 | resource_func=theforeman.search_template_kind,
234 | resource_specs=[template_kind_name])
235 | if res:
236 | data['template_kind_id'] = res[0]["id"]
237 |
238 | if not snippet and operatingsystems is not None:
239 | data['operatingsystems'] = get_resources(resource_type='operatingsystem',
240 | resource_func=theforeman.search_operatingsystem,
241 | resource_specs=operatingsystems,
242 | search_field='title')
243 |
244 | if not config_template:
245 | try:
246 | config_template = theforeman.create_config_template(data=data)
247 | return True, config_template
248 | except ForemanError as e:
249 | module.fail_json(msg='Could not create config template: {0}'.format(e.message))
250 |
251 | if not templates_equal(data, config_template):
252 | try:
253 | if config_template['locked']:
254 | unlock = {'id': config_template.get('id'), 'locked': False}
255 | theforeman.update_config_template(id=config_template.get('id'), data=unlock)
256 | if data.get('locked', config_template['locked']):
257 | data['locked'] = False
258 | theforeman.update_config_template(id=config_template.get('id'), data=data)
259 | data['locked'] = True
260 | config_template = theforeman.update_config_template(id=config_template.get('id'), data=data)
261 | return True, config_template
262 | except ForemanError as e:
263 | module.fail_json(msg='Could not update config template: {0}'.format(e.message))
264 |
265 | return False, config_template
266 |
267 |
268 | def main():
269 | global module
270 | module = AnsibleModule(
271 | argument_spec=dict(
272 | audit_comment=dict(type='str', required=False),
273 | name=dict(type='str', required=True),
274 | locked=dict(type='bool', required=False),
275 | operatingsystems=dict(type='list', required=False),
276 | template=dict(type='str', required=False),
277 | template_file=dict(type='str', required=False),
278 | template_kind_name=dict(type='str', required=False),
279 | snippet=dict(type='bool', required=False),
280 | organizations=dict(type='list', required=False),
281 | locations=dict(type='list', required=False),
282 | state=dict(type='str', default='present', choices=['present', 'absent']),
283 | foreman_host=dict(type='str', default='127.0.0.1'),
284 | foreman_port=dict(type='str', default='443'),
285 | foreman_user=dict(type='str', required=True),
286 | foreman_pass=dict(type='str', required=True, no_log=True),
287 | foreman_ssl=dict(type='bool', default=True)
288 | ),
289 | )
290 |
291 | if not foremanclient_found:
292 | module.fail_json(msg='python-foreman module is required. See https://github.com/Nosmoht/python-foreman.')
293 | if has_import_error:
294 | module.fail_json(msg=import_error_msg)
295 |
296 | changed, config_template = ensure()
297 | module.exit_json(changed=changed, config_template=config_template)
298 |
299 |
300 | from ansible.module_utils.basic import *
301 |
302 | if __name__ == '__main__':
303 | main()
304 |
--------------------------------------------------------------------------------
/foreman_domain.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding: utf-8 -*-
3 | #
4 | # Ansible module to manage Foreman domain resources.
5 | #
6 | # This module is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This software is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with this software. If not, see .
18 |
19 | DOCUMENTATION = '''
20 | ---
21 | module: foreman_domain
22 | short_description: Manage Foreman Domains using Foreman API v2
23 | description:
24 | - Create and delete Foreman Domain using Foreman API v2
25 | options:
26 | name:
27 | description: Domain name
28 | required: true
29 | fullname:
30 | description: Description of the domain
31 | required: false
32 | default: None
33 | dns_proxy:
34 | description: dns_proxy
35 | state:
36 | description: Domain state
37 | required: false
38 | default: present
39 | choices: ["present", "absent"]
40 | organizations:
41 | description: List of organizations the domain should be assigned to
42 | required: false
43 | locations:
44 | description: List of locations the domain should be assigned to
45 | required: false
46 | foreman_host:
47 | description: Hostname or IP address of Foreman system
48 | required: false
49 | default: 127.0.0.1
50 | foreman_port:
51 | description: Port of Foreman API
52 | required: false
53 | default: 443
54 | foreman_user:
55 | description: Username to be used to authenticate on Foreman
56 | required: true
57 | default: None
58 | foreman_pass:
59 | description: Password to be used to authenticate user on Foreman
60 | required: true
61 | default: None
62 | foreman_ssl:
63 | description: Enable SSL when connecting to Foreman API
64 | required: false
65 | default: true
66 | notes:
67 | - Requires the python-foreman package to be installed. See https://github.com/Nosmoht/python-foreman.
68 | version_added: "2.0"
69 | author: "Thomas Krahn (@nosmoht)"
70 | '''
71 |
72 | EXAMPLES = '''
73 | - name: Ensure example.com
74 | foreman_domain:
75 | name: example.com
76 | fullname: Example domain
77 | state: present
78 | organizations:
79 | - Torchlight
80 | locations:
81 | - Cardiff
82 | - London
83 | foreman_host: 127.0.0.1
84 | foreman_port: 443
85 | foreman_user: admin
86 | foreman_pass: secret
87 | '''
88 |
89 | try:
90 | from foreman.foreman import *
91 | except ImportError:
92 | foremanclient_found = False
93 | else:
94 | foremanclient_found = True
95 |
96 | try:
97 | from ansible.module_utils.foreman_utils import *
98 |
99 | has_import_error = False
100 | except ImportError as e:
101 | has_import_error = True
102 | import_error_msg = str(e)
103 |
104 |
105 | def domains_equal(data, domain, comparable_keys):
106 | if not all(data.get(key, None) == domain.get(key, None) for key in comparable_keys):
107 | return False
108 | if not organizations_equal(data, domain):
109 | return False
110 | if not locations_equal(data, domain):
111 | return False
112 | return True
113 |
114 |
115 | def get_resources(resource_type, resource_specs, theforeman):
116 | result = []
117 | for item in resource_specs:
118 | search_data = dict()
119 | if isinstance(item, dict):
120 | for key in item:
121 | search_data[key] = item[key]
122 | else:
123 | search_data['name'] = item
124 | try:
125 | resource = theforeman.search_resource(resource_type=resource_type, data=search_data)
126 | if not resource:
127 | module.fail_json(
128 | msg='Could not find resource type {resource_type} defined as {spec}'.format(
129 | resource_type=resource_type,
130 | spec=item))
131 | result.append(resource)
132 | except ForemanError as e:
133 | module.fail_json(msg='Could not search resource type {resource_type} defined as {spec}: {error}'.format(
134 | resource_type=resource_type, spec=item, error=e.message))
135 | return result
136 |
137 |
138 | def ensure(module):
139 | comparable_keys = ['name', 'fullname']
140 | name = module.params['name']
141 | fullname = module.params['fullname']
142 | state = module.params['state']
143 | dns_proxy = module.params['dns_proxy']
144 | organizations = module.params['organizations']
145 | locations = module.params['locations']
146 |
147 | theforeman = init_foreman_client(module)
148 |
149 | data = {'name': name}
150 |
151 | try:
152 | domain = theforeman.search_domain(data=data)
153 | if domain:
154 | domain = theforeman.get_domain(id=domain.get('id'))
155 | except ForemanError as e:
156 | module.fail_json(msg='Could not get domain: {0}'.format(e.message))
157 |
158 | if organizations:
159 | data['organization_ids'] = get_organization_ids(module, theforeman, organizations)
160 |
161 | if locations:
162 | data['location_ids'] = get_location_ids(module, theforeman, locations)
163 |
164 | data['fullname'] = fullname
165 | if dns_proxy:
166 | data['dns_id'] = get_resources(resource_type='smart_proxies', resource_specs=[dns_proxy],
167 | theforeman=theforeman)[0].get('id')
168 |
169 | if not domain and state == 'present':
170 | try:
171 | domain = theforeman.create_domain(data=data)
172 | return True, domain
173 | except ForemanError as e:
174 | module.fail_json(msg='Could not create domain: {0}'.format(e.message))
175 |
176 | if domain:
177 | if state == 'absent':
178 | try:
179 | domain = theforeman.delete_domain(id=domain.get('id'))
180 | return True, domain
181 | except ForemanError as e:
182 | module.fail_json(msg='Could not delete domain: {0}'.format(e.message))
183 |
184 | if not domains_equal(data, domain, comparable_keys):
185 | try:
186 | domain = theforeman.update_domain(id=domain.get('id'), data=data)
187 | return True, domain
188 | except ForemanError as e:
189 | module.fail_json(msg='Could not update domain: {0}'.format(e.message))
190 |
191 | return False, domain
192 |
193 |
194 | def main():
195 | global module
196 |
197 | module = AnsibleModule(
198 | argument_spec=dict(
199 | name=dict(type='str', required=True),
200 | fullname=dict(type='str', required=False),
201 | dns_proxy=dict(type='str', required=False),
202 | state=dict(type='str', default='present', choices=['present', 'absent']),
203 | organizations=dict(type='list', required=False),
204 | locations=dict(type='list', required=False),
205 | foreman_host=dict(type='str', default='127.0.0.1'),
206 | foreman_port=dict(type='str', default='443'),
207 | foreman_user=dict(type='str', required=True),
208 | foreman_pass=dict(type='str', required=True, no_log=True),
209 | foreman_ssl=dict(type='bool', default=True)
210 | ),
211 | )
212 |
213 | if not foremanclient_found:
214 | module.fail_json(msg='python-foreman module is required. See https://github.com/Nosmoht/python-foreman.')
215 |
216 | changed, domain = ensure(module)
217 | module.exit_json(changed=changed, domain=domain)
218 |
219 |
220 | from ansible.module_utils.basic import *
221 |
222 | if __name__ == '__main__':
223 | main()
224 |
--------------------------------------------------------------------------------
/foreman_environment.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding: utf-8 -*-
3 | #
4 | # Ansible module to manage Foreman environment resources.
5 | #
6 | # This module is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This software is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with this software. If not, see .
18 |
19 | DOCUMENTATION = '''
20 | ---
21 | module: foreman_environment
22 | short_description: Manage Foreman Environment using Foreman API v2
23 | description:
24 | - Create and delete Foreman Environments using Foreman API v2
25 | options:
26 | name:
27 | description: Name of environment
28 | required: true
29 | state:
30 | description: State of environment
31 | required: false
32 | default: present
33 | choices: ["present", "absent"]
34 | organizations:
35 | description: List of organizations the environement should be assigned to
36 | required: false
37 | locations:
38 | description: List of locations the environement should be assigned to
39 | required: false
40 | foreman_host:
41 | description: Hostname or IP address of Foreman system
42 | required: false
43 | default: 127.0.0.1
44 | foreman_port:
45 | description: Port of Foreman API
46 | required: false
47 | default: 443
48 | foreman_user:
49 | description: Username to be used to authenticate on Foreman
50 | required: true
51 | foreman_pass:
52 | description: Password to be used to authenticate user on Foreman
53 | required: true
54 | foreman_ssl:
55 | description: Enable SSL when connecting to Foreman API
56 | required: false
57 | default: true
58 | notes:
59 | - Requires the python-foreman package to be installed. See https://github.com/Nosmoht/python-foreman.
60 | version_added: "2.0"
61 | author: "Thomas Krahn (@nosmoht)"
62 | '''
63 |
64 | EXAMPLES = '''
65 | - name: Ensure Production environment is present
66 | foreman_environment:
67 | name: Production
68 | state: present
69 | organizations:
70 | - Prod INC
71 | locations:
72 | - New York City
73 | - Washington DC
74 | foreman_host: 127.0.0.1
75 | foreman_port: 443
76 | foreman_user: admin
77 | foreman_pass: secret
78 | '''
79 |
80 | try:
81 | from foreman.foreman import *
82 |
83 | foremanclient_found = True
84 | except ImportError:
85 | foremanclient_found = False
86 |
87 | def get_organization_ids(module, theforeman, organizations):
88 | result = []
89 | for i in range(0, len(organizations)):
90 | try:
91 | organization = theforeman.search_organization(data={'name': organizations[i]})
92 | if not organization:
93 | module.fail_json('Could not find Organization {0}'.format(organizations[i]))
94 | result.append(organization.get('id'))
95 | except ForemanError as e:
96 | module.fail_json('Could not get Organizations: {0}'.format(e.message))
97 | return result
98 |
99 |
100 | def get_location_ids(module, theforeman, locations):
101 | result = []
102 | for i in range(0, len(locations)):
103 | try:
104 | location = theforeman.search_location(data={'name':locations[i]})
105 | if not location:
106 | module.fail_json('Could not find Location {0}'.format(locations[i]))
107 | result.append(location.get('id'))
108 | except ForemanError as e:
109 | module.fail_json('Could not get Locations: {0}'.format(e.message))
110 | return result
111 |
112 |
113 | def ensure(module):
114 | name = module.params['name']
115 | state = module.params['state']
116 | organizations = module.params['organizations']
117 | locations = module.params['locations']
118 |
119 | foreman_host = module.params['foreman_host']
120 | foreman_port = module.params['foreman_port']
121 | foreman_user = module.params['foreman_user']
122 | foreman_pass = module.params['foreman_pass']
123 | foreman_ssl = module.params['foreman_ssl']
124 |
125 | theforeman = Foreman(hostname=foreman_host,
126 | port=foreman_port,
127 | username=foreman_user,
128 | password=foreman_pass,
129 | ssl=foreman_ssl)
130 |
131 | data = {'name': name}
132 |
133 | try:
134 | env = theforeman.search_environment(data=data)
135 | except ForemanError as e:
136 | module.fail_json(msg='Could not get environment: {0}'.format(e.message))
137 |
138 | if organizations:
139 | data['organization_ids'] = get_organization_ids(module, theforeman, organizations)
140 |
141 | if locations:
142 | data['location_ids'] = get_location_ids(module, theforeman, locations)
143 |
144 |
145 | if not env and state == 'present':
146 | try:
147 | env = theforeman.create_environment(data=data)
148 | return True, env
149 | except ForemanError as e:
150 | module.fail_json(msg='Could not create environment: {0}'.format(e.message))
151 |
152 | if env and state == 'absent':
153 | try:
154 | env = theforeman.delete_environment(id=env.get('id'))
155 | return True, env
156 | except ForemanError as e:
157 | module.fail_json(msg='Could not delete environment: {0}'.format(e.message))
158 |
159 | return False, env
160 |
161 |
162 | def main():
163 | module = AnsibleModule(
164 | argument_spec=dict(
165 | name=dict(type='str', required=True),
166 | state=dict(type='str', default='present', choices=['present', 'absent']),
167 | organizations=dict(type='list', required=False),
168 | locations=dict(type='list', required=False),
169 | foreman_host=dict(type='str', default='127.0.0.1'),
170 | foreman_port=dict(type='str', default='443'),
171 | foreman_user=dict(type='str', required=True),
172 | foreman_pass=dict(type='str', required=True, no_log=True),
173 | foreman_ssl=dict(type='bool', default=True)
174 | ),
175 | )
176 |
177 | if not foremanclient_found:
178 | module.fail_json(msg='python-foreman module is required. See https://github.com/Nosmoht/python-foreman.')
179 |
180 | changed, env = ensure(module)
181 | module.exit_json(changed=changed, environment=env)
182 |
183 |
184 | from ansible.module_utils.basic import *
185 |
186 | if __name__ == '__main__':
187 | main()
--------------------------------------------------------------------------------
/foreman_external_usergroup.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding: utf-8 -*-
3 | #
4 | # Ansible module to manage Foreman external_usergroup resources.
5 | #
6 | # This module is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This software is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with this software. If not, see .
18 | #
19 | # (C) 2017 Guido Günther
20 |
21 | DOCUMENTATION = '''
22 | ---
23 | module: foreman_external_usergroup
24 | short_description: Manage Foreman External Usergroup using Foreman API v2
25 | description:
26 | - Create and delete Foreman External Usergroups using Foreman API v2
27 | options:
28 | name:
29 | description: name of the external usergroup
30 | required: true
31 | auth_source:
32 | description: auth source of this usergroup
33 | required: true
34 | usergroup:
35 | description: usergroup to link to.
36 | required: true
37 | state:
38 | description: State of usergroup
39 | required: false
40 | default: present
41 | choices: ["present", "absent"]
42 | foreman_host:
43 | description: Hostname or IP address of Foreman system
44 | required: false
45 | default: 127.0.0.1
46 | foreman_port:
47 | description: Port of Foreman API
48 | required: false
49 | default: 443
50 | foreman_user:
51 | description: Username to be used to authenticate on Foreman
52 | required: true
53 | foreman_pass:
54 | description: Password to be used to authenticate user on Foreman
55 | required: true
56 | foreman_ssl:
57 | description: Enable SSL when connecting to Foreman API
58 | required: false
59 | default: true
60 | notes:
61 | - Requires the python-foreman package to be installed. See https://github.com/Nosmoht/python-foreman.
62 | - This module does currently not update already existing groups
63 | version_added: "2.0"
64 | author: "Guido Gúnther (@agx)"
65 | '''
66 |
67 | EXAMPLES = '''
68 | - name: Ensure LDAP group wheel is linked to foreman usergroup admin
69 | foreman_external_usergroup:
70 | name: wheel
71 | auth_source: LDAP-Server
72 | usergroup: admin
73 | state: present
74 | foreman_host: 127.0.0.1
75 | foreman_port: 443
76 | foreman_user: admin
77 | foreman_pass: secret
78 | '''
79 |
80 | try:
81 | from foreman.foreman import *
82 | foremanclient_found = True
83 | except ImportError:
84 | foremanclient_found = False
85 |
86 |
87 | def get_id(module, theforeman, res_type, name, field='name'):
88 | result = None
89 | try:
90 | searcher = getattr(theforeman, "search_{0}".format(res_type))
91 | except AttributeError:
92 | module.fail_json(msg="Don't know how to search for {0}".format(res_type))
93 |
94 | try:
95 | res = searcher(data={field: name})
96 | if not res:
97 | module.fail_json(msg="Could not find '{0}' of type {1}".format(name, res_type))
98 | result = res.get('id')
99 | except ForemanError as e:
100 | module.fail_json(msg="Could not get '{0}' of type {1}: {2}".format(name,
101 | res_type,
102 | e.message))
103 | return result
104 |
105 |
106 | def ensure(module):
107 | name = module.params['name']
108 | state = module.params['state']
109 | auth_source = module.params['auth_source']
110 | usergroup = module.params['usergroup']
111 | ext_group = None
112 |
113 | foreman_host = module.params['foreman_host']
114 | foreman_port = module.params['foreman_port']
115 | foreman_user = module.params['foreman_user']
116 | foreman_pass = module.params['foreman_pass']
117 | foreman_ssl = module.params['foreman_ssl']
118 |
119 | theforeman = Foreman(hostname=foreman_host,
120 | port=foreman_port,
121 | username=foreman_user,
122 | password=foreman_pass,
123 | ssl=foreman_ssl)
124 | try:
125 | group = theforeman.search_usergroup({'name': usergroup})
126 | except ForemanError as e:
127 | module.fail_json(msg='Could not get group usergroup: {0}'.format(e.message))
128 |
129 | data = dict(name=name)
130 | try:
131 | ext_groups = theforeman.get_external_usergroups(group['id'])
132 | except ForemanError as e:
133 | module.fail_json(msg='Could not get external usergroups for {0}: {1}'.format(name, e.message))
134 |
135 | for e in ext_groups:
136 | if e['name'] == name:
137 | ext_group = e
138 | break
139 |
140 | if not ext_group and state == 'present':
141 | data['usergroup_id'] = group['id']
142 | data['auth_source_id'] = get_id(module, theforeman, 'auth_source_ldap', auth_source)
143 |
144 | try:
145 | ext_group = theforeman.create_external_usergroup(group['id'], data=data)
146 | return True, ext_group
147 | except ForemanError as e:
148 | module.fail_json(msg='Could not create external usergroup: {0}'.format(e.message))
149 |
150 | if ext_group and state == 'absent':
151 | try:
152 | ext_group = theforeman.delete_external_usergroup(group_id=group['id'], ext_group_id=ext_group['id'])
153 | except ForemanError as e:
154 | module.fail_json(msg='Could not delete external usergroup: {0}'.format(e.message))
155 | return True, ext_group
156 |
157 | return False, ext_group
158 |
159 |
160 | def main():
161 | module = AnsibleModule(
162 | argument_spec=dict(
163 | state=dict(type='str', default='present', choices=['present', 'absent']),
164 | name=dict(type='str', required=True),
165 | usergroup=dict(type='str', required=True),
166 | auth_source=dict(type='str', required=True),
167 | foreman_host=dict(type='str', default='127.0.0.1'),
168 | foreman_port=dict(type='str', default='443'),
169 | foreman_user=dict(type='str', required=True),
170 | foreman_pass=dict(type='str', required=True, no_log=True),
171 | foreman_ssl=dict(type='bool', default=True)
172 | ),
173 | )
174 |
175 | if not foremanclient_found:
176 | module.fail_json(msg='python-foreman module is required. See https://github.com/Nosmoht/python-foreman.')
177 |
178 | changed, usergroup = ensure(module)
179 | module.exit_json(changed=changed, usergroup=usergroup)
180 |
181 |
182 | from ansible.module_utils.basic import *
183 |
184 | if __name__ == '__main__':
185 | main()
186 |
--------------------------------------------------------------------------------
/foreman_filter.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding: utf-8 -*-
3 | #
4 | # Ansible module to manage Foreman filter resources.
5 | #
6 | # This module is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This software is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with this software. If not, see .
18 | #
19 | # (C) 2017 Guido Günther
20 |
21 | DOCUMENTATION = '''
22 | ---
23 | module: foreman_filter
24 | short_description: Manage Foreman Filter using Foreman API v2
25 | description:
26 | - Create and delete Foreman Filters using Foreman API v2
27 | options:
28 | role:
29 | description: role this filter belongs tue
30 | required: true
31 | resource_type:
32 | description: resource type this permission affects
33 | required: true
34 | permissions:
35 | description: List of permissions
36 | required: true
37 | state:
38 | description: State of filter
39 | required: false
40 | default: present
41 | choices: ["present", "absent"]
42 | foreman_host:
43 | description: Hostname or IP address of Foreman system
44 | required: false
45 | default: 127.0.0.1
46 | foreman_port:
47 | description: Port of Foreman API
48 | required: false
49 | default: 443
50 | foreman_user:
51 | description: Username to be used to authenticate on Foreman
52 | required: true
53 | foreman_pass:
54 | description: Password to be used to authenticate user on Foreman
55 | required: true
56 | foreman_ssl:
57 | description: Enable SSL when connecting to Foreman API
58 | required: false
59 | default: true
60 | notes:
61 | - Requires the python-foreman package to be installed. See https://github.com/Nosmoht/python-foreman.
62 | version_added: "2.0"
63 | author: "Thomas Krahn (@nosmoht)"
64 | '''
65 |
66 | EXAMPLES = '''
67 | - name: Ensure Production filter is present
68 | foreman_filter:
69 | role: "Host Power"
70 | resource: Host
71 | permissions:
72 | - power_hosts
73 | state: present
74 | foreman_host: 127.0.0.1
75 | foreman_port: 443
76 | foreman_user: admin
77 | foreman_pass: secret
78 | '''
79 |
80 | try:
81 | from foreman.foreman import *
82 |
83 | foremanclient_found = True
84 | except ImportError:
85 | foremanclient_found = False
86 |
87 | def get_permission_ids(module, theforeman, resource_type, permissions):
88 | result = []
89 | for i in range(0, len(permissions)):
90 | try:
91 | permission = theforeman.search_permission(data={'resource_type': resource_type,
92 | 'name': permissions[i]})
93 | if not permission:
94 | module.fail_json(msg='Could not find Permission {0} for {1}'.format(permissions[i],
95 | resource_type))
96 | result.append(permission.get('id'))
97 | except ForemanError as e:
98 | module.fail_json(msg='Could not get Permissions: {0}'.format(e.message))
99 | return result
100 |
101 |
102 | def get_role_id(module, theforeman, rolename):
103 | try:
104 | role = theforeman.search_role(data={'name': rolename})
105 | if not role:
106 | module.fail_json(msg='Could not find role {0}'.format(rolename))
107 | i = role.get('id')
108 | if not i:
109 | module.fail_json(msg='Can\'t find id for {0} in {1}'.format(rolename, role))
110 | except ForemanError as e:
111 | module.fail_json(msg='Could not get role: {0}'.format(e.message))
112 | return role['id']
113 |
114 |
115 | def ensure(module):
116 | state = module.params['state']
117 | role = module.params['role']
118 | resource_type = module.params['resource_type']
119 | permissions = module.params['permissions']
120 |
121 | foreman_host = module.params['foreman_host']
122 | foreman_port = module.params['foreman_port']
123 | foreman_user = module.params['foreman_user']
124 | foreman_pass = module.params['foreman_pass']
125 | foreman_ssl = module.params['foreman_ssl']
126 |
127 | theforeman = Foreman(hostname=foreman_host,
128 | port=foreman_port,
129 | username=foreman_user,
130 | password=foreman_pass,
131 | ssl=foreman_ssl)
132 |
133 | data = dict()
134 |
135 | data['permission_ids'] = get_permission_ids(module, theforeman, resource_type, permissions)
136 | data['role_id'] = get_role_id(module, theforeman, role)
137 |
138 | filters = theforeman.search_filter(data={'role_id': data['role_id']})
139 | if not filters and state == 'present':
140 | try:
141 | filtr = theforeman.create_filter(data=data)
142 | return True, filtr
143 | except ForemanError as e:
144 | module.fail_json(msg='Could not create filter: {0}'.format(e.message))
145 |
146 | if filters:
147 | if type(filters) != type([]):
148 | filters = [filters]
149 |
150 | if state == 'present':
151 | for f in filters:
152 | if sorted(p['id'] for p in f['permissions']) == sorted(data['permission_ids']):
153 | return False, f
154 | try:
155 | # We have no way to decide if perms should be updated so best
156 | # we can do is create a new one
157 | filtr = theforeman.create_filter(data=data)
158 | return True, filtr
159 | except ForemanError as e:
160 | module.fail_json(msg='Could not create filter: {0}'.format(e.message))
161 | elif state == 'absent':
162 | for f in filters:
163 | if sorted(p['id'] for p in f['permissions']) == sorted(data['permission_ids']):
164 | try:
165 | filtr = theforeman.delete_filter(id=f['id'])
166 | return True, filtr
167 | except ForemanError as e:
168 | module.fail_json(msg='Could not delete filter: {0}'.format(e.message))
169 | return False, filtr
170 |
171 |
172 | def main():
173 | module = AnsibleModule(
174 | argument_spec=dict(
175 | state=dict(type='str', default='present', choices=['present', 'absent']),
176 | role=dict(type='str', required=True),
177 | resource_type=dict(type='str', required=True),
178 | permissions=dict(type='list', required=True),
179 | foreman_host=dict(type='str', default='127.0.0.1'),
180 | foreman_port=dict(type='str', default='443'),
181 | foreman_user=dict(type='str', required=True),
182 | foreman_pass=dict(type='str', required=True, no_log=True),
183 | foreman_ssl=dict(type='bool', default=True)
184 | ),
185 | )
186 |
187 | if not foremanclient_found:
188 | module.fail_json(msg='python-foreman module is required. See https://github.com/Nosmoht/python-foreman.')
189 |
190 | changed, filtr = ensure(module)
191 | module.exit_json(changed=changed, filter=filtr)
192 |
193 |
194 | from ansible.module_utils.basic import *
195 |
196 | if __name__ == '__main__':
197 | main()
198 |
--------------------------------------------------------------------------------
/foreman_global_parameter.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding: utf-8 -*-
3 | #
4 | # Ansible module to manage Foreman global parameters.
5 | #
6 | # This module is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This software is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with this software. If not, see .
18 |
19 | DOCUMENTATION = '''
20 | ---
21 | module: foreman_global_parameter
22 | short_description: Manage Foreman global parameter using Foreman API v2
23 | description:
24 | - Update Foreman global parameter using Foreman API v2
25 | options:
26 | name:
27 | description: Global parameter name
28 | required: true
29 | value:
30 | description: parameter value
31 | required: true
32 | foreman_host:
33 | description: Hostname or IP address of Foreman system
34 | required: false
35 | default: 127.0.0.1
36 | foreman_port:
37 | description: Port of Foreman API
38 | required: false
39 | default: 443
40 | foreman_user:
41 | description: Username to be used to authenticate on Foreman
42 | required: true
43 | foreman_pass:
44 | description: Password to be used to authenticate user on Foreman
45 | required: true
46 | foreman_ssl:
47 | description: Enable SSL when connecting to Foreman API
48 | required: false
49 | default: true
50 | notes:
51 | - Requires the python-foreman package to be installed. See https://github.com/Nosmoht/python-foreman.
52 | version_added: "2.0"
53 | author: "Radim Janca "
54 | '''
55 |
56 | EXAMPLES = '''
57 | - name: Ensure Global parameter
58 | foreman_global_parameter:
59 | name: baud
60 | value: 115200
61 | state: present
62 | foreman_host: foreman.example.com
63 | foreman_port: 443
64 | foreman_user: admin
65 | foreman_pass: secret
66 | '''
67 |
68 | try:
69 | from foreman.foreman import *
70 | foremanclient_found = True
71 | except ImportError:
72 | foremanclient_found = False
73 |
74 | def ensure(module):
75 | global theforeman
76 |
77 | name = module.params['name']
78 | value = module.params['value']
79 | state = module.params['state']
80 | global_parameter = None
81 |
82 | foreman_host = module.params['foreman_host']
83 | foreman_port = module.params['foreman_port']
84 | foreman_user = module.params['foreman_user']
85 | foreman_pass = module.params['foreman_pass']
86 | foreman_ssl = module.params['foreman_ssl']
87 |
88 | theforeman = Foreman(hostname=foreman_host,
89 | port=foreman_port,
90 | username=foreman_user,
91 | password=foreman_pass,
92 | ssl=foreman_ssl)
93 |
94 | data = {'name': name}
95 |
96 | try:
97 | global_parameter = theforeman.search_common_parameter(data=data)
98 | except ForemanError as e:
99 | module.fail_json(msg='Could not get global parameter: {0}'.format(e.message))
100 |
101 | data['value'] = value
102 |
103 | if state == 'present':
104 | if not global_parameter:
105 | try:
106 | global_parameter = theforeman.create_common_parameter(data=data)
107 | return True, global_parameter
108 | except ForemanError as e:
109 | module.fail_json(msg='Could not create global parameter: {0}'.format(e.message))
110 | else:
111 | if data['value'] != global_parameter['value']:
112 | try:
113 | global_parameter = theforeman.update_resource(resource_type='common_parameters',
114 | resource_id=global_parameter.get('id'),
115 | data=data)
116 | return True, global_parameter
117 | except ForemanError as e:
118 | module.fail_json(msg='Could not update global parameter: {0}'.format(e.message))
119 |
120 | if state == 'absent':
121 | if global_parameter:
122 | try:
123 | global_parameter = theforeman.delete_common_parameter(id=global_parameter.get('id'))
124 | return True, global_parameter
125 | except ForemanError as e:
126 | module.fail_json(msg='Could not remove global parameter: {0}'.format(e.message))
127 |
128 | return False, global_parameter
129 |
130 | def main():
131 | global module
132 |
133 | module = AnsibleModule(
134 | argument_spec=dict(
135 | name=dict(type='str', required=True),
136 | value=dict(type='str', required=True),
137 | state=dict(type='str', default='present', choices=['present', 'absent']),
138 | foreman_host=dict(type='str', default='127.0.0.1'),
139 | foreman_port=dict(type='str', default='443'),
140 | foreman_user=dict(type='str', required=True),
141 | foreman_pass=dict(type='str', required=True, no_log=True),
142 | foreman_ssl=dict(type='bool', default=True)
143 | ),
144 | )
145 |
146 | if not foremanclient_found:
147 | module.fail_json(msg='python-foreman module is required. See https://github.com/Nosmoht/python-foreman.')
148 |
149 | changed, global_parameter = ensure(module)
150 | module.exit_json(changed=changed, global_parameter=global_parameter)
151 |
152 | # import module snippets
153 | from ansible.module_utils.basic import *
154 |
155 | if __name__ == '__main__':
156 | main()
157 |
--------------------------------------------------------------------------------
/foreman_host_check.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding: utf-8 -*-
3 | #
4 | # Ansible module to get status form Foreman host resources.
5 | #
6 | # This module is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This software is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with this software. If not, see .
18 |
19 | DOCUMENTATION = '''
20 | ---
21 | module: foreman_host
22 | short_description: Get Foreman host info using Foreman API v2
23 | description:
24 | - Get Foreman host info using Foreman API v2
25 | options:
26 | name:
27 | description: Hostgroup name
28 | required: true
29 | default: None
30 | domain:
31 | description: Domain name
32 | required: false
33 | default: None
34 | foreman_host:
35 | description: Hostname or IP address of Foreman system
36 | required: false
37 | default: 127.0.0.1
38 | foreman_port:
39 | description: Port of Foreman API
40 | required: false
41 | default: 443
42 | foreman_user:
43 | description: Username to be used to authenticate on Foreman
44 | required: true
45 | foreman_pass:
46 | description: Password to be used to authenticate user on Foreman
47 | required: true
48 | foreman_ssl:
49 | description: Enable SSL when connecting to Foreman API
50 | required: false
51 | default: true
52 | notes:
53 | - Requires the python-foreman package to be installed. See https://github.com/Nosmoht/python-foreman.
54 | version_added: "2.0"
55 | author: "Thomas Krahn (@nosmoht)"
56 | '''
57 |
58 |
59 | try:
60 | from foreman.foreman import *
61 | except ImportError:
62 | foremanclient_found = False
63 | else:
64 | foremanclient_found = True
65 |
66 | try:
67 | from ansible.module_utils.foreman_utils import *
68 |
69 | has_import_error = False
70 | except ImportError as e:
71 | has_import_error = True
72 | import_error_msg = str(e)
73 |
74 |
75 | def ensure():
76 | name = module.params['name']
77 | domain_name = module.params['domain']
78 |
79 | theforeman = init_foreman_client(module)
80 |
81 | if domain_name:
82 | if domain_name in name:
83 | host_name = name
84 | else:
85 | host_name = '{name}.{domain}'.format(name=name, domain=domain_name)
86 | else:
87 | host_name = name
88 |
89 | data = dict(name=host_name)
90 |
91 | try:
92 | host = theforeman.search_host(data=data)
93 | if host:
94 | host = theforeman.get_host(id=host.get('id'))
95 | return False, host
96 | except ForemanError as e:
97 | module.fail_json(msg='Error while searching host: {0}'.format(e.message))
98 |
99 | module.fail_json(msg="Host '{host}' does not exist.'".format(host=host_name))
100 |
101 |
102 | def main():
103 | global module
104 | module = AnsibleModule(
105 | argument_spec=dict(
106 | name=dict(type='str', required=True),
107 | domain=dict(type='str', default=None),
108 | foreman_host=dict(type='str', default='127.0.0.1'),
109 | foreman_port=dict(type='str', default='443'),
110 | foreman_user=dict(type='str', required=True),
111 | foreman_pass=dict(type='str', required=True, no_log=True),
112 | foreman_ssl=dict(type='bool', default=True)
113 | ),
114 | )
115 |
116 | if not foremanclient_found:
117 | module.fail_json(
118 | msg='python-foreman module is required. See https://github.com/Nosmoht/python-foreman.')
119 |
120 | changed, host = ensure()
121 | module.exit_json(changed=changed, host=host)
122 |
123 |
124 | from ansible.module_utils.basic import *
125 |
126 | if __name__ == '__main__':
127 | main()
128 |
--------------------------------------------------------------------------------
/foreman_hostgroup.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding: utf-8 -*-
3 | #
4 | # Ansible module to manage Foreman hostgroup resources.
5 | #
6 | # This module is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This software is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with this software. If not, see .
18 |
19 | DOCUMENTATION = '''
20 | ---
21 | module: foreman_hostgroup
22 | short_description: Manage Foreman Hostgroup using Foreman API v2
23 | description:
24 | - Manage Foreman Hostgroup using Foreman API v2
25 | options:
26 | architecture:
27 | description: Architecture name
28 | required: False
29 | default: None
30 | domain:
31 | description: Domain name
32 | required: False
33 | default: None
34 | environment:
35 | description: Environment name
36 | required: False
37 | default: None
38 | medium:
39 | description: Medium name
40 | required: False
41 | default: None
42 | name:
43 | description: Hostgroup name
44 | required: True
45 | operatingsystem:
46 | description: Operatingsystem name
47 | required: False
48 | default: None
49 | parameters:
50 | description: List of parameters and values
51 | required: false
52 | default: None
53 | partition_table:
54 | description: Partition table name
55 | required: False
56 | default: None
57 | pxe_loader:
58 | description: PXE Loader
59 | required: False
60 | default: None
61 | realm:
62 | description: Realm name
63 | required: false
64 | default: None
65 | root_pass:
66 | description: root password
67 | required: false
68 | default: None
69 | force_update:
70 | description: forces update of hostgroup, usefull when in need of password update
71 | required: false
72 | default: false
73 | smart_proxy:
74 | description: Smart Proxy name
75 | required: False
76 | default: None
77 | subnet:
78 | description: Subnet name
79 | required: False
80 | default: None
81 | state:
82 | description: Hostgroup state
83 | required: false
84 | default: present
85 | choices: ["present", "absent"]
86 | locations: List of locations the subnet should be assigned to
87 | required: false
88 | default: None
89 | organizations: List of organizations the subnet should be assigned to
90 | required: false
91 | default: None
92 | foreman_host:
93 | description: Hostname or IP address of Foreman system
94 | required: false
95 | default: 127.0.0.1
96 | foreman_port:
97 | description: Port of Foreman API
98 | required: false
99 | default: 443
100 | foreman_user:
101 | description: Username to be used to authenticate on Foreman
102 | required: true
103 | foreman_pass:
104 | description: Password to be used to authenticate user on Foreman
105 | required: true
106 | foreman_ssl:
107 | description: Enable SSL when connecting to Foreman API
108 | required: false
109 | default: true
110 | notes:
111 | - Requires the python-foreman package to be installed. See https://github.com/Nosmoht/python-foreman.
112 | version_added: "2.0"
113 | author: "Thomas Krahn (@nosmoht)"
114 | '''
115 |
116 | EXAMPLES = '''
117 | - name: Ensure Hostgroup
118 | foreman_hostgroup:
119 | name: MyHostgroup
120 | state: present
121 | architecture: x86_64
122 | domain: MyDomain
123 | operatingsystem: MyOS
124 | subnet: MySubnet
125 | foreman_host: 127.0.0.1
126 | foreman_port: 443
127 | foreman_user: admin
128 | foreman_pass: secret
129 | '''
130 |
131 | try:
132 | from foreman.foreman import *
133 | except ImportError:
134 | foremanclient_found = False
135 | else:
136 | foremanclient_found = True
137 |
138 | try:
139 | from ansible.module_utils.foreman_utils import *
140 |
141 | has_import_error = False
142 | except ImportError as e:
143 | has_import_error = True
144 | import_error_msg = str(e)
145 |
146 |
147 | def get_resource(module, resource_type, resource_func, resource_name, search_title=False):
148 | """
149 | Look for a resource within Foreman Database. Return the resource if found or fail.
150 | If the Resource could not be found by name search by title.
151 |
152 | :param module:
153 | :param resource_type:
154 | :param resource_func:
155 | :param resource_name:
156 | :return:
157 | """
158 | try:
159 | result = resource_func(data=dict(name=resource_name))
160 | if not result and search_title:
161 | result = resource_func(data=dict(title=resource_name))
162 | if not result:
163 | module.fail_json(msg='{0} {1} not found'.format(resource_type, resource_name))
164 | except ForemanError as e:
165 | module.fail_json(msg='Error while getting {0}: {1}'.format(resource_type, e.message))
166 | return result
167 |
168 |
169 | def split_parent(name):
170 | """
171 | Split hostgroup name in parent part and name:
172 |
173 | >>> split_parent("a/b/c")
174 | ('c', 'a/b')
175 | """
176 | if '/' in name:
177 | parent, name = name.rsplit('/', 1)
178 | else:
179 | return name, None
180 | return name, parent
181 |
182 |
183 | def hostgroups_equal(data, hostgroup):
184 | comparable_keys = set(data.keys()).intersection(set(
185 | ['name', 'title', 'architecture_id', 'compute_profile_id', 'domain_id', 'environment_id', 'medium_id',
186 | 'operatingsystem_id', 'ptable_id', 'realm_id', 'puppet_proxy_id', 'subnet_id', 'parent_id', 'pxe_loader']))
187 | if not all(str(data.get(key, None)) == str(hostgroup.get(key, None)) for key in comparable_keys):
188 | return False
189 | if not organizations_equal(data, hostgroup):
190 | return False
191 | if not locations_equal(data, hostgroup):
192 | return False
193 | return True
194 |
195 |
196 | def ensure(module):
197 | changed = False
198 | full_name = module.params['name']
199 | short_name, parent_name = split_parent(full_name)
200 | architecture_name = module.params['architecture']
201 | compute_profile_name = module.params['compute_profile']
202 | domain_name = module.params['domain']
203 | environment_name = module.params['environment']
204 | medium_name = module.params['medium']
205 | operatingsystem_name = module.params['operatingsystem']
206 | partition_table_name = module.params['partition_table']
207 | pxe_loader = module.params['pxe_loader']
208 | realm_name = module.params['realm']
209 | root_pass = module.params['root_pass']
210 | smart_proxy_name = module.params['smart_proxy']
211 | subnet_name = module.params['subnet']
212 | locations = module.params['locations']
213 | organizations = module.params['organizations']
214 | state = module.params['state']
215 | parameters = module.params['parameters']
216 | force_update = module.params['force_update']
217 |
218 | theforeman = init_foreman_client(module)
219 |
220 | data = {'title': full_name, 'name': short_name}
221 |
222 | try:
223 | hostgroup = theforeman.search_hostgroup(data=data)
224 | if hostgroup:
225 | hostgroup = theforeman.get_hostgroup(id=hostgroup.get('id'))
226 | except ForemanError as e:
227 | module.fail_json(msg='Could not get hostgroup: {0}'.format(e.message))
228 |
229 | if state == 'absent':
230 | if hostgroup:
231 | try:
232 | hostgroup = theforeman.delete_hostgroup(id=hostgroup.get('id'))
233 | return True, hostgroup
234 | except ForemanError as e:
235 | module.fail_json(msg='Could not delete hostgroup: {0}'.format(e.message))
236 | else:
237 | return False, hostgroup
238 |
239 | if organizations:
240 | data['organization_ids'] = get_organization_ids(module, theforeman, organizations)
241 |
242 | if locations:
243 | data['location_ids'] = get_location_ids(module, theforeman, locations)
244 |
245 | # Architecture
246 | if architecture_name:
247 | architecture = get_resource(module=module,
248 | resource_type=ARCHITECTURE,
249 | resource_func=theforeman.search_architecture,
250 | resource_name=architecture_name)
251 | data['architecture_id'] = str(architecture.get('id'))
252 |
253 | # Compute Profile
254 | if compute_profile_name:
255 | compute_profile = get_resource(module=module,
256 | resource_type=COMPUTE_PROFILE,
257 | resource_func=theforeman.search_compute_profile,
258 | resource_name=compute_profile_name)
259 | data['compute_profile_id'] = str(compute_profile.get('id'))
260 |
261 | # Domain
262 | if domain_name:
263 | domain = get_resource(module=module,
264 | resource_type=DOMAIN,
265 | resource_func=theforeman.search_domain,
266 | resource_name=domain_name)
267 | data['domain_id'] = str(domain.get('id'))
268 |
269 | # Environment
270 | if environment_name:
271 | environment = get_resource(module=module,
272 | resource_type=ENVIRONMENT,
273 | resource_func=theforeman.search_environment,
274 | resource_name=environment_name)
275 | data['environment_id'] = str(environment.get('id'))
276 |
277 | # Medium
278 | if medium_name:
279 | medium = get_resource(module=module,
280 | resource_type=MEDIUM,
281 | resource_func=theforeman.search_medium,
282 | resource_name=medium_name)
283 | data['medium_id'] = str(medium.get('id'))
284 |
285 | # Operatingssystem
286 | if operatingsystem_name:
287 | operatingsystem = get_resource(module=module,
288 | resource_type=OPERATINGSYSTEM,
289 | resource_func=theforeman.search_operatingsystem,
290 | resource_name=operatingsystem_name,
291 | search_title=True)
292 | data['operatingsystem_id'] = str(operatingsystem.get('id'))
293 |
294 | # Partition Table
295 | if partition_table_name:
296 | partition_table = get_resource(module=module,
297 | resource_type=PARTITION_TABLE,
298 | resource_func=theforeman.search_partition_table,
299 | resource_name=partition_table_name)
300 | data['ptable_id'] = str(partition_table.get('id'))
301 |
302 | # PXE loader
303 | if pxe_loader:
304 | data['pxe_loader'] = pxe_loader
305 |
306 | # Realm
307 | if realm_name:
308 | realm = get_resource(module=module,
309 | resource_type=REALM,
310 | resource_func=theforeman.search_realm,
311 | resource_name=realm_name)
312 | data['realm_id'] = str(realm.get('id'))
313 | # Root password
314 | if root_pass:
315 | data['root_pass'] = root_pass
316 |
317 | # Smart Proxy
318 | if smart_proxy_name:
319 | smart_proxy = get_resource(module=module,
320 | resource_type=SMART_PROXY,
321 | resource_func=theforeman.search_smart_proxy,
322 | resource_name=smart_proxy_name)
323 | data['puppet_proxy_id'] = str(smart_proxy.get('id'))
324 |
325 | # Subnet
326 | if subnet_name:
327 | subnet = get_resource(module=module,
328 | resource_type=SUBNET,
329 | resource_func=theforeman.search_subnet,
330 | resource_name=subnet_name)
331 | data['subnet_id'] = str(subnet.get('id'))
332 |
333 | # Parent
334 | if parent_name:
335 | parent = get_resource(module=module,
336 | resource_type=HOSTGROUP,
337 | resource_func=theforeman.search_hostgroup,
338 | search_title=True,
339 | resource_name=parent_name)
340 | data['parent_id'] = str(parent.get('id'))
341 |
342 | # state == present
343 | if not hostgroup:
344 | try:
345 | hostgroup = theforeman.create_hostgroup(data=data)
346 | changed = True
347 | except ForemanError as e:
348 | module.fail_json(msg='Could not create hostgroup: {0}'.format(e.message))
349 | elif not hostgroups_equal(data, hostgroup) or force_update:
350 | try:
351 | hostgroup = theforeman.update_hostgroup(id=hostgroup.get('id'), data=data)
352 | changed = True
353 | except ForemanError as e:
354 | module.fail_json(msg='Could not update hostgroup: {0}'.format(e.message))
355 |
356 | hostgroup_id = hostgroup.get('id')
357 |
358 | # Parameters
359 | if parameters:
360 | try:
361 | hostgroup_parameters = theforeman.get_hostgroup_parameters(hostgroup_id=hostgroup_id)
362 | except ForemanError as e:
363 | module.fail_json(
364 | msg='Could not get hostgroup parameters: {0}'.format(e.message))
365 |
366 | # Delete parameters which are not defined
367 | for hostgroup_param in hostgroup_parameters:
368 | hostgroup_param_name = hostgroup_param.get('name')
369 | defined_params = [item for item in parameters if item.get(
370 | 'name') == hostgroup_param_name]
371 | if not defined_params:
372 | try:
373 | theforeman.delete_hostgroup_parameter(
374 | hostgroup_id=hostgroup_id, parameter_id=hostgroup_param.get('id'))
375 | except ForemanError as e:
376 | module.fail_json(msg='Could not delete host parameter {name}: {error}'.format(
377 | name=hostgroup_param_name))
378 | changed = True
379 |
380 | # Create and update parameters
381 | for param in parameters:
382 | hostgroup_params = [item for item in hostgroup_parameters if item.get('name') == param.get('name')]
383 | if not hostgroup_params:
384 | try:
385 | theforeman.create_hostgroup_parameter(hostgroup_id=hostgroup_id, data=param)
386 | except ForemanError as e:
387 | module.fail_json(
388 | msg='Could not create host parameter {param_name}: {error}'.format(param_name=param.get('name'),
389 | error=e.message))
390 | changed = True
391 | else:
392 | for hostgroup_param in hostgroup_params:
393 | hostgroup_value = hostgroup_param.get('value')
394 | param_value = param.get('value')
395 | if isinstance(param_value, list):
396 | param_value = ','.join(param_value)
397 | # Replace \n seems to be needed. Otherwise some strings are
398 | # always changed although they look equal
399 | if hostgroup_value.replace('\n', '') != param_value.replace('\n', ''):
400 | try:
401 | theforeman.update_hostgroup_parameter(hostgroup_id=hostgroup_id,
402 | parameter_id=hostgroup_param.get('id'),
403 | data=param)
404 | except ForemanError as e:
405 | module.fail_json(
406 | msg='Could not update host parameter {param_name}: {error}'.format(
407 | param_name=param.get('name'), error=e.message))
408 | changed = True
409 |
410 | return changed, hostgroup
411 |
412 |
413 | def main():
414 | module = AnsibleModule(
415 | argument_spec=dict(
416 | name=dict(type='str', required=True),
417 | architecture=dict(type='str', default=None),
418 | compute_profile=dict(type='str', default=None),
419 | domain=dict(type='str', default=None),
420 | environment=dict(type='str', default=None),
421 | medium=dict(type='str', default=None),
422 | operatingsystem=dict(type='str', default=None),
423 | parameters=dict(type='list', default=None),
424 | partition_table=dict(type='str', default=None),
425 | pxe_loader=dict(type='str', default=None),
426 | realm=dict(type='str', default=None),
427 | root_pass=dict(type='str', default=None, no_log=True),
428 | force_update=dict(type='bool', default=False),
429 | smart_proxy=dict(type='str', default=None),
430 | subnet=dict(type='str', default=None),
431 | state=dict(type='str', default='present', choices=['present', 'absent']),
432 | locations=dict(type='list', required=False),
433 | organizations=dict(type='list', required=False),
434 | foreman_host=dict(type='str', default='127.0.0.1'),
435 | foreman_port=dict(type='str', default='443'),
436 | foreman_user=dict(type='str', required=True),
437 | foreman_pass=dict(type='str', required=True, no_log=True),
438 | foreman_ssl=dict(type='bool', default=True)
439 | ),
440 | )
441 |
442 | if not foremanclient_found:
443 | module.fail_json(msg='python-foreman module is required. See https://github.com/Nosmoht/python-foreman.')
444 |
445 | changed, hostgroup = ensure(module)
446 | module.exit_json(changed=changed, hostgroup=hostgroup)
447 |
448 | # import module snippets
449 | from ansible.module_utils.basic import *
450 |
451 | if __name__ == '__main__':
452 | main()
453 |
--------------------------------------------------------------------------------
/foreman_image.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding: utf-8 -*-
3 | #
4 | # Ansible module to manage Foreman operating system resources.
5 | #
6 | # This module is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This software is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with this software. If not, see .
18 | #
19 |
20 | DOCUMENTATION = '''
21 | ---
22 | module: foreman_image
23 | short_description:
24 | - Manage Foreman images using Foreman API v2.
25 | description:
26 | - Create, update and and delete Foreman images using Foreman API v2
27 | options:
28 | name:
29 | description: Image name as used in Foreman
30 | required: true
31 | state:
32 | description: image state
33 | required: false
34 | default: 'present'
35 | choices: ['present', 'absent']
36 | uuid:
37 | operatingsystem:
38 | description: Operatingsystem used on the image
39 | required: True
40 | architecture:
41 | description: Architecture the image is for
42 | required: True
43 | uuid:
44 | description: UUID of the image
45 | required: True
46 | user:
47 | description: User used to log into the image
48 | required: False
49 | default: root
50 | foreman_host:
51 | description: Hostname or IP address of Foreman system
52 | required: false
53 | default: 127.0.0.1
54 | foreman_port:
55 | description: Port of Foreman API
56 | required: false
57 | default: 443
58 | foreman_user:
59 | description: Username to be used to authenticate on Foreman
60 | required: true
61 | foreman_pass:
62 | description: Password to be used to authenticate user on Foreman
63 | required: true
64 | foreman_ssl:
65 | description: Enable SSL when connecting to Foreman API
66 | required: false
67 | default: true
68 | notes:
69 | - Requires the python-foreman package to be installed. See https://github.com/Nosmoht/python-foreman.
70 | version_added: "2.0"
71 | author: "Guido Günther "
72 | '''
73 |
74 | EXAMPLES = '''
75 | - name: Ensure Debian Jessie Image
76 | foreman_image:
77 | name: Debian Jessie Minimal
78 | architecture: x86_64
79 | operatingsystem: DebianJessie
80 | uuid: /path/to/image
81 | state: present
82 | foreman_host: 127.0.0.1
83 | foreman_port: 443
84 | foreman_user: admin
85 | foreman_pass: secret
86 | '''
87 |
88 | try:
89 | from foreman.foreman import *
90 |
91 | foremanclient_found = True
92 | except ImportError:
93 | foremanclient_found = False
94 |
95 |
96 | def get_resources(resource_type, resource_func, resource_name, search_field='name'):
97 | if not resource_name:
98 | return None
99 | search_data = dict()
100 | search_data[search_field] = resource_name
101 | try:
102 | resource = resource_func(data=search_data)
103 | if not resource:
104 | module.fail_json(
105 | msg='Could not find resource type {resource_type} specified as {name}'.format(
106 | resource_type=resource_type, name=resource_name))
107 | except ForemanError as e:
108 | module.fail_json(msg='Could not search resource type {resource_type} specified as {name}: {error}'.format(
109 | resource_type=resource_type, name=resource_name, error=e.message))
110 | return resource
111 |
112 |
113 | def ensure():
114 | name = module.params['name']
115 | compute_resource_name = module.params['compute_resource']
116 | state = module.params['state']
117 |
118 | data = dict(name=name)
119 |
120 | try:
121 | compute_resource = theforeman.search_compute_resource(data=dict(name=compute_resource_name))
122 | except ForemanError as e:
123 | module.fail_json(msg='Could not find compute resource {0}: {1}'.format(compute_resource_name, e.message))
124 |
125 | if not compute_resource:
126 | module.fail_json(msg='Could not find compute resource {0}'.format(compute_resource_name))
127 |
128 | cid = compute_resource['id']
129 | try:
130 | images = theforeman.get_compute_resource_images(compute_resource['id'])
131 | for i in images:
132 | if i['name'] == name:
133 | image = i
134 | break
135 | else:
136 | image = None
137 | except ForemanError as e:
138 | module.fail_json(msg='Could not get images: {0}'.format(e.message))
139 |
140 | if state == 'absent':
141 | if image:
142 | try:
143 | image = theforeman.delete_compute_resource_image(cid, image.get('id'))
144 | return True, image
145 | except ForemanError as e:
146 | module.fail_json(msg='Could not delete image: {0}'.format(e.message))
147 |
148 | return False, image
149 |
150 | data['compute_resource_id'] = cid
151 | data['uuid'] = module.params['uuid']
152 | data['username'] = module.params['user']
153 | if module.params['password']:
154 | data['password'] = module.params['password']
155 | data['architecture_id'] = get_resources(resource_type='architecture',
156 | resource_func=theforeman.search_architecture,
157 | resource_name=module.params['architecture'])['id']
158 | data['operatingsystem_id'] = get_resources(resource_type='operatingsystem',
159 | resource_func=theforeman.search_operatingsystem,
160 | resource_name=module.params['operatingsystem'],
161 | search_field='title')['id']
162 |
163 | if not image:
164 | try:
165 | image = theforeman.create_compute_resource_image(compute_resource_id=cid,
166 | data=data)
167 | return True, image
168 | except ForemanError as e:
169 | module.fail_json(msg='Could not create image: {0}'.format(e.message))
170 | else:
171 | data['id'] = image['id']
172 |
173 | if not all(data[key] == image.get(key, data[key]) for key in data.keys()):
174 | try:
175 | new_data = dict(compute_resource_id=cid, id=image['id'], image=data)
176 | image = theforeman.update_compute_resource_image(compute_resource_id=cid,
177 | data=new_data)
178 | return True, image
179 | except ForemanError as e:
180 | module.fail_json(msg='Could not update image: {0}'.format(e.message))
181 |
182 | return False, image
183 |
184 |
185 | def main():
186 | global module
187 | global theforeman
188 |
189 | module = AnsibleModule(
190 | argument_spec=dict(
191 | name=dict(type='str', required=True),
192 | compute_resource=dict(type='str', required=True),
193 | architecture=dict(type='str', required=True),
194 | operatingsystem=dict(operatingsystem='str', required=True),
195 | uuid=dict(type='str', required=True),
196 | user=dict(type='str', default='root'),
197 | password=dict(type='str', default=None, no_log=True),
198 | state=dict(type='str', default='present', choices=['present', 'absent']),
199 | foreman_host=dict(type='str', default='127.0.0.1'),
200 | foreman_port=dict(type='str', default='443'),
201 | foreman_user=dict(type='str', required=True),
202 | foreman_pass=dict(type='str', required=True, no_log=True),
203 | foreman_ssl=dict(type='bool', default=True)
204 | ),
205 | )
206 |
207 | if not foremanclient_found:
208 | module.fail_json(msg='python-foreman module is required. See https://github.com/Nosmoht/python-foreman.')
209 |
210 | foreman_host = module.params['foreman_host']
211 | foreman_port = module.params['foreman_port']
212 | foreman_user = module.params['foreman_user']
213 | foreman_pass = module.params['foreman_pass']
214 | foreman_ssl = module.params['foreman_ssl']
215 |
216 | theforeman = Foreman(hostname=foreman_host,
217 | port=foreman_port,
218 | username=foreman_user,
219 | password=foreman_pass,
220 | ssl=foreman_ssl)
221 |
222 | changed, image = ensure()
223 | module.exit_json(changed=changed, image=image)
224 |
225 |
226 | from ansible.module_utils.basic import *
227 |
228 | if __name__ == '__main__':
229 | main()
230 |
--------------------------------------------------------------------------------
/foreman_ldap.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding: utf-8 -*-
3 | #
4 | # Ansible module to manage Foreman ldap resources.
5 | #
6 | # This module is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This software is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with this software. If not, see .
18 |
19 | DOCUMENTATION = '''
20 | ---
21 | module: foreman_ldap
22 | short_description:
23 | - Manage Foreman Ldap auth sources using Foreman API v2.
24 | description:
25 | - Create, opdate and and delete Foreman Ldaps using Foreman API v2
26 | options:
27 | name:
28 | description: LDAP name
29 | required: True
30 | host:
31 | description: LDAP host to use
32 | required: True
33 | port:
34 | description: LDAP port
35 | required: False
36 | default: 389
37 | tls:
38 | description: use LDAPS
39 | required: False
40 | default: False),
41 | base_dn:
42 | description: Search base
43 | required: False
44 | account:
45 | description: account for acces LDAP
46 | required: False
47 | account_password:
48 | description: password for LDAP account
49 | required: False
50 | attr_login:
51 | description: LDAP attribute used as login
52 | required: False
53 | attr_firstname:
54 | description: LDAP attribute used as firstname
55 | required: False
56 | attr_lastname
57 | description: LDAP attribute used as lastname
58 | required: False
59 | attr_mail:
60 | description: LDAP attribute used as mail
61 | required:False
62 | attr_photo:
63 | description: LDAP attribute used as photo
64 | required:False
65 | onthefly_register:
66 | description: Autocreate users authenticated by LDAP in foreman
67 | required:False
68 | usergroup_sync:
69 | description: Sync LDAP user groups automatically
70 | required:False
71 | groups_base:
72 | description: Base DN for group search used by usergroup_sync
73 | required:False
74 | server_type:
75 | description: LDAP server type, one of: posix, free_ipa, active_directory
76 | required:False
77 | ldap_filter:
78 | description: LDAP users acceptance filter
79 | required:False
80 | organizations:
81 | description:
82 | - List of organization the LDAP should be assigned to
83 | required: false
84 | locations:
85 | description:
86 | - List of locations the LDAP should be assigned to
87 | required: false
88 | state:
89 | description: Ldap state
90 | required: False
91 | default: present
92 | choices: ["present", "absent"]
93 | foreman_host:
94 | description: Hostname or IP address of Foreman system
95 | required: false
96 | default: 127.0.0.1
97 | foreman_port:
98 | description: Port of Foreman API
99 | required: false
100 | default: 443
101 | foreman_user:
102 | description: Username to be used to authenticate on Foreman
103 | required: true
104 | foreman_pass:
105 | description: Password to be used to authenticate user on Foreman
106 | required: true
107 | foreman_ssl:
108 | description: Enable SSL when connecting to Foreman API
109 | required: false
110 | default: true
111 | notes:
112 | - Requires the python-foreman package to be installed. See https://github.com/Nosmoht/python-foreman.
113 | version_added: "2.0"
114 | author: "Thomas Krahn (@nosmoht)"
115 | '''
116 |
117 | EXAMPLES = '''
118 | - name: A test ldap server
119 | foreman_ldap:
120 | name: Test LDAP
121 | host: 127.0.0.1
122 | state: present
123 | foreman_host: 127.0.0.1
124 | foreman_port: 443
125 | foreman_user: admin
126 | foreman_pass: secret
127 | '''
128 |
129 | try:
130 | from foreman.foreman import *
131 | except ImportError:
132 | foremanclient_found = False
133 | else:
134 | foremanclient_found = True
135 |
136 | try:
137 | from ansible.module_utils.foreman_utils import *
138 |
139 | has_import_error = False
140 | except ImportError as e:
141 | has_import_error = True
142 | import_error_msg = str(e)
143 |
144 |
145 | def get_user_ids(module, theforeman, users):
146 | result = []
147 | for i in range(0, len(users)):
148 | try:
149 | user = theforeman.search_user(data={'login': users[i]})
150 | if not user:
151 | module.fail_json('Could not find user {0}'.format(users[i]))
152 | result.append(user.get('id'))
153 | except ForemanError as e:
154 | module.fail_json('Could not get user: {0}'.format(e.message))
155 | return result
156 |
157 |
158 | def ldaps_equal(data, ldap, cmp_keys):
159 | for key in cmp_keys:
160 | if (key in data) and (data.get(key) != ldap.get(key)):
161 | return False
162 | if not organizations_equal(data, ldap):
163 | return False
164 | if not locations_equal(data, ldap):
165 | return False
166 | return True
167 |
168 |
169 | def ensure(module):
170 | name = module.params['name']
171 | state = module.params['state']
172 | organizations = module.params['organizations']
173 | locations = module.params['locations']
174 |
175 | theforeman = init_foreman_client(module)
176 |
177 | cmp_keys = ['host', 'port', 'base_dn', 'account', 'attr_login', 'attr_firstname',
178 | 'attr_lastname', 'attr_mail', 'attr_photo', 'onthefly_register',
179 | 'usergroup_sync', 'ldap_filter', 'tls', 'groups_base', 'server_type']
180 | keys = cmp_keys + ['account_password']
181 |
182 | data = {'name': name}
183 |
184 | try:
185 | ldap = theforeman.search_auth_source_ldap(data=data)
186 | if ldap:
187 | ldap = theforeman.get_auth_source_ldap(id=ldap.get('id'))
188 | except ForemanError as e:
189 | module.fail_json(msg='Could not get ldap: {0}'.format(e.message))
190 |
191 | for key in keys:
192 | if module.params[key]:
193 | data[key] = module.params[key]
194 | if organizations is not None:
195 | data['organization_ids'] = get_organization_ids(module, theforeman, organizations)
196 | if locations is not None:
197 | data['location_ids'] = get_location_ids(module, theforeman, locations)
198 |
199 | if not ldap and state == 'present':
200 | try:
201 | theforeman.create_auth_source_ldap(data=data)
202 | return True
203 | except ForemanError as e:
204 | module.fail_json(msg='Could not create ldap: {0}'.format(e.message))
205 |
206 | if ldap:
207 | if state == 'absent':
208 | try:
209 | theforeman.delete_auth_source_ldap(id=ldap.get('id'))
210 | return True
211 | except ForemanError as e:
212 | module.fail_json('Could not delete ldap: {0}'.format(e.message))
213 |
214 | if not ldaps_equal(data, ldap, cmp_keys):
215 | try:
216 | ldap = theforeman.update_auth_source_ldap(id=ldap.get('id'), data=data)
217 | return True, ldap
218 | except ForemanError as e:
219 | module.fail_json(msg='Could not update hostgroup: {0}'.format(e.message))
220 | return False
221 |
222 |
223 | def main():
224 | module = AnsibleModule(
225 | argument_spec=dict(
226 | name=dict(type='str', required=True),
227 | state=dict(type='str', default='present', choices=['present', 'absent']),
228 | host=dict(type='str', required=True),
229 | port=dict(type='int', required=False, default=389),
230 | tls=dict(type='bool', required=False, default=False),
231 | base_dn=dict(type='str', required=False),
232 | account=dict(type='str', required=False),
233 | account_password=dict(type='str', required=False, no_log=True),
234 | attr_login=dict(type='str', required=False),
235 | attr_firstname=dict(type='str', required=False),
236 | attr_lastname=dict(type='str', required=False),
237 | attr_mail=dict(type='str', required=False),
238 | attr_photo=dict(type='str', required=False),
239 | onthefly_register=dict(type='bool', required=False),
240 | usergroup_sync=dict(type='bool', required=False),
241 | groups_base=dict(type='str', required=False),
242 | server_type=dict(type='str', required=False, choices=['posix', 'free_ipa', 'active_directory']),
243 | ldap_filter=dict(type='str', required=False),
244 | organizations=dict(type='list', required=False),
245 | locations=dict(type='list', required=False),
246 | foreman_host=dict(type='str', default='127.0.0.1'),
247 | foreman_port=dict(type='str', default='443'),
248 | foreman_user=dict(type='str', required=True),
249 | foreman_pass=dict(type='str', required=True, no_log=True),
250 | foreman_ssl=dict(type='bool', default=True)
251 | ),
252 | )
253 |
254 | if not foremanclient_found:
255 | module.fail_json(msg='python-foreman module is required. See https://github.com/Nosmoht/python-foreman.')
256 | if has_import_error:
257 | module.fail_json(msg=import_error_msg)
258 |
259 | changed = ensure(module)
260 | module.exit_json(changed=changed, name=module.params['name'])
261 |
262 |
263 | from ansible.module_utils.basic import *
264 |
265 | if __name__ == '__main__':
266 | main()
267 |
--------------------------------------------------------------------------------
/foreman_location.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding: utf-8 -*-
3 | #
4 | # Ansible module to manage Foreman location resources.
5 | #
6 | # This module is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This software is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with this software. If not, see .
18 |
19 | DOCUMENTATION = '''
20 | ---
21 | module: foreman_location
22 | short_description:
23 | - Manage Foreman Location using Foreman API v2. This module requires Katello to be installed in addition to Foreman.
24 | description:
25 | - Create, opdate and and delete Foreman Locations using Foreman API v2
26 | options:
27 | name:
28 | description: Location name
29 | required: True
30 | state:
31 | description: Location state
32 | required: False
33 | default: present
34 | choices: ["present", "absent"]
35 | users:
36 | description: List of usernames assigned to the location
37 | required: False
38 | default: None
39 | foreman_host:
40 | description: Hostname or IP address of Foreman system
41 | required: false
42 | default: 127.0.0.1
43 | foreman_port:
44 | description: Port of Foreman API
45 | required: false
46 | default: 443
47 | foreman_user:
48 | description: Username to be used to authenticate on Foreman
49 | required: true
50 | foreman_pass:
51 | description: Password to be used to authenticate user on Foreman
52 | required: true
53 | foreman_ssl:
54 | description: Enable SSL when connecting to Foreman API
55 | required: false
56 | default: true
57 | notes:
58 | - Requires the python-foreman package to be installed. See https://github.com/Nosmoht/python-foreman.
59 | version_added: "2.0"
60 | author: "Thomas Krahn (@nosmoht)"
61 | '''
62 |
63 | EXAMPLES = '''
64 | - name: Ensure New York Datacenter
65 | foreman_location:
66 | name: MY-DC
67 | state: present
68 | users:
69 | - pinky
70 | - brain
71 | foreman_host: 127.0.0.1
72 | foreman_port: 443
73 | foreman_user: admin
74 | foreman_pass: secret
75 | '''
76 |
77 | try:
78 | from foreman.foreman import *
79 | except ImportError:
80 | foremanclient_found = False
81 | else:
82 | foremanclient_found = True
83 |
84 |
85 | def get_user_ids(module, theforeman, users):
86 | result = []
87 | for i in range(0, len(users)):
88 | try:
89 | user = theforeman.search_user(data={'login': users[i]})
90 | if not user:
91 | module.fail_json('Could not find user {0}'.format(users[i]))
92 | result.append(user.get('id'))
93 | except ForemanError as e:
94 | module.fail_json('Could not get user: {0}'.format(e.message))
95 | return result
96 |
97 |
98 | def ensure(module):
99 | name = module.params['name']
100 | state = module.params['state']
101 | users = module.params['users']
102 |
103 | foreman_host = module.params['foreman_host']
104 | foreman_port = module.params['foreman_port']
105 | foreman_user = module.params['foreman_user']
106 | foreman_pass = module.params['foreman_pass']
107 | foreman_ssl = module.params['foreman_ssl']
108 |
109 | theforeman = Foreman(hostname=foreman_host,
110 | port=foreman_port,
111 | username=foreman_user,
112 | password=foreman_pass,
113 | ssl=foreman_ssl)
114 |
115 | data = {'name': name}
116 |
117 | try:
118 | location = theforeman.search_location(data=data)
119 | except ForemanError as e:
120 | module.fail_json(msg='Could not get location: {0}'.format(e.message))
121 |
122 | if users:
123 | data['user_ids'] = get_user_ids(module, theforeman, users)
124 |
125 | if not location and state == 'present':
126 | try:
127 | theforeman.create_location(data=data)
128 | return True
129 | except ForemanError as e:
130 | module.fail_json(msg='Could not create location: {0}'.format(e.message))
131 |
132 | if location:
133 | if state == 'absent':
134 | try:
135 | theforeman.delete_location(id=location.get('id'))
136 | return True
137 | except ForemanError as e:
138 | module.fail_json('Could not delete location: {0}'.format(e.message))
139 |
140 | return False
141 |
142 |
143 | def main():
144 | module = AnsibleModule(
145 | argument_spec=dict(
146 | name=dict(type='str', required=True),
147 | state=dict(type='str', default='present', choices=['present', 'absent']),
148 | users=dict(type='list', required=False),
149 | foreman_host=dict(type='str', default='127.0.0.1'),
150 | foreman_port=dict(type='str', default='443'),
151 | foreman_user=dict(type='str', required=True),
152 | foreman_pass=dict(type='str', required=True, no_log=True),
153 | foreman_ssl=dict(type='bool', default=True)
154 | ),
155 | )
156 |
157 | if not foremanclient_found:
158 | module.fail_json(msg='python-foreman module is required. See https://github.com/Nosmoht/python-foreman.')
159 |
160 | changed = ensure(module)
161 | module.exit_json(changed=changed, name=module.params['name'])
162 |
163 |
164 | from ansible.module_utils.basic import *
165 |
166 | if __name__ == '__main__':
167 | main()
168 |
--------------------------------------------------------------------------------
/foreman_medium.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding: utf-8 -*-
3 | #
4 | # Ansible module to manage Foreman medium resources.
5 | #
6 | # This module is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This software is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with this software. If not, see .
18 |
19 | DOCUMENTATION = '''
20 | ---
21 | module: foreman_medium
22 | short_description: Manage Foreman media using Foreman API v2
23 | description:
24 | - Create, update and delete Foreman media using Foreman API v2
25 | options:
26 | name:
27 | description:
28 | - Medium name, a combination of name '*' and state 'absent' can be used to clean up, by deleting all present media
29 | required: true
30 | path:
31 | description:
32 | - The path to the medium, can be a URL or a valid NFS server (exclusive of the architecture).
33 | required: true
34 | os_family:
35 | description:
36 | - Operating system family
37 | required: false
38 | state:
39 | description:
40 | - Medium state, , a combination of name '*' and state 'absent' can be used to clean up, by deleting all present media
41 | required: false
42 | default: 'present'
43 | choices: ['present', 'absent']
44 | locations:
45 | description:
46 | - List of locations the medium should be assigned to
47 | required: false
48 | organizations:
49 | description:
50 | - List of organization the medium should be assigned to
51 | required: false
52 | foreman_host:
53 | description:
54 | - Hostname or IP address of Foreman system
55 | required: false
56 | default: 127.0.0.1
57 | foreman_port:
58 | description:
59 | - Port of Foreman API
60 | required: false
61 | default: 443
62 | foreman_user:
63 | description:
64 | - Username to be used to authenticate on Foreman
65 | required: true
66 | foreman_pass:
67 | description:
68 | - Password to be used to authenticate user on Foreman
69 | required: true
70 | foreman_ssl:
71 | description: Enable SSL when connecting to Foreman API
72 | required: false
73 | default: true
74 | notes:
75 | - Requires the python-foreman package to be installed. See https://github.com/Nosmoht/python-foreman.
76 | version_added: "2.0"
77 | author: "Thomas Krahn (@nosmoht)"
78 | '''
79 |
80 | EXAMPLES = '''
81 | - name: Medium
82 | foreman_medium:
83 | name: CentOS mirror
84 | path: http://mirror.centos.org/centos/$version/os/$arch
85 | os_family: Redhat
86 | locations:
87 | - Munich
88 | organizations:
89 | - Development
90 | - DevOps
91 | state: present
92 | foreman_user: admin
93 | foreman_pass: secret
94 | foreman_host: foreman.example.com
95 | foreman_port: 443
96 |
97 | - name: delete all Media
98 | foreman_medium:
99 | name: *
100 | state: absent
101 | ...
102 | '''
103 |
104 | try:
105 | from foreman.foreman import *
106 |
107 | foremanclient_found = True
108 | except ImportError:
109 | foremanclient_found = False
110 |
111 | try:
112 | from ansible.module_utils.foreman_utils import *
113 |
114 | has_import_error = False
115 | except ImportError as e:
116 | has_import_error = True
117 | import_error_msg = str(e)
118 |
119 |
120 | def medium_equal(data, medium, module):
121 | comparable_keys = set(data.keys()).intersection(set(
122 | ['path', 'os_family']))
123 | if not all(data.get(key, None) == medium.get(key, None) for key in comparable_keys):
124 | return False
125 | if not organizations_equal(data, medium):
126 | return False
127 | if not locations_equal(data, medium):
128 | return False
129 | return True
130 |
131 |
132 | def ensure(module):
133 | name = module.params['name']
134 | path = module.params['path']
135 | state = module.params['state']
136 | os_family = module.params['os_family']
137 | organizations = module.params['organizations']
138 | locations = module.params['locations']
139 |
140 | foreman_host = module.params['foreman_host']
141 | foreman_port = module.params['foreman_port']
142 | foreman_user = module.params['foreman_user']
143 | foreman_pass = module.params['foreman_pass']
144 | foreman_ssl = module.params['foreman_ssl']
145 |
146 | theforeman = Foreman(hostname=foreman_host,
147 | port=foreman_port,
148 | username=foreman_user,
149 | password=foreman_pass,
150 | ssl=foreman_ssl)
151 |
152 | data = {'name': name}
153 |
154 | if name == '*' and state == 'absent':
155 | try:
156 | all_media_list = theforeman.get_resources(resource_type=MEDIA)
157 | for element in all_media_list:
158 | theforeman.delete_medium(id=element.get('id'))
159 | return True, all_media_list
160 | except ForemanError as e:
161 | module.fail_json(msg='Error in deleting all existing media: {0}'.format(e.message))
162 |
163 | try:
164 | medium = theforeman.search_medium(data=data)
165 | if medium:
166 | medium = theforeman.get_medium(id=medium.get('id'))
167 | except ForemanError as e:
168 | module.fail_json(msg='Could not get medium: {0}'.format(e.message))
169 |
170 | if path:
171 | data['path'] = path
172 | if os_family:
173 | data['os_family'] = os_family
174 | if organizations is not None:
175 | data['organization_ids'] = get_organization_ids(module, theforeman, organizations)
176 | if locations is not None:
177 | data['location_ids'] = get_location_ids(module, theforeman, locations)
178 |
179 | if not medium and state == 'present':
180 | try:
181 | medium = theforeman.create_medium(data=data)
182 | return True, medium
183 | except ForemanError as e:
184 | module.fail_json(msg='Could not create medium: {0}'.format(e.message))
185 |
186 | if medium:
187 | if state == 'absent':
188 | try:
189 | medium = theforeman.delete_medium(id=medium.get('id'))
190 | return True, medium
191 | except ForemanError as e:
192 | module.fail_json('Could not delete medium: {0}'.format(e.message))
193 | if not medium_equal(data, medium, module):
194 | try:
195 | medium = theforeman.update_medium(id=medium.get('id'), data=data)
196 | return True, medium
197 | except ForemanError as e:
198 | module.fail_json(msg='Could not update medium: {0}'.format(e.message))
199 |
200 | return False, medium
201 |
202 |
203 | def main():
204 | module = AnsibleModule(
205 | argument_spec=dict(
206 | name=dict(type='str', required=True),
207 | path=dict(type='str', required=False),
208 | os_family=dict(type='str', required=False),
209 | organizations=dict(type='list', required=False),
210 | locations=dict(type='list', required=False),
211 | state=dict(type='str', default='present', choices=['present', 'absent']),
212 | foreman_host=dict(type='str', default='127.0.0.1'),
213 | foreman_port=dict(type='str', default='443'),
214 | foreman_user=dict(type='str', required=True),
215 | foreman_pass=dict(type='str', required=True, no_log=True),
216 | foreman_ssl=dict(type='bool', default=True)
217 | ),
218 | )
219 |
220 | if not foremanclient_found:
221 | module.fail_json(msg='python-foreman module is required. See https://github.com/Nosmoht/python-foreman.')
222 | if has_import_error:
223 | module.fail_json(msg=import_error_msg)
224 |
225 | changed, medium = ensure(module)
226 | module.exit_json(changed=changed, medium=medium)
227 |
228 |
229 | from ansible.module_utils.basic import *
230 |
231 | if __name__ == '__main__':
232 | main()
233 |
--------------------------------------------------------------------------------
/foreman_operatingsystem.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding: utf-8 -*-
3 | #
4 | # Ansible module to manage Foreman operating system resources.
5 | #
6 | # This module is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This software is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with this software. If not, see .
18 |
19 | DOCUMENTATION = '''
20 | ---
21 | module: foreman_operatingsystem
22 | short_description:
23 | - Manage Foreman Operatingsystems using Foreman API v2.
24 | description:
25 | - Create, update and and delete Foreman Operatingsystems using Foreman API v2
26 | options:
27 | description:
28 | description: OS description
29 | required: false
30 | default: None
31 | name:
32 | description: OS name
33 | required: true
34 | major:
35 | description: OS major version
36 | required: true
37 | minor:
38 | description: OS minor version
39 | required: false
40 | default: None
41 | family:
42 | description: Family
43 | required: false
44 | default: None
45 | release_name:
46 | description: Release name
47 | required: false
48 | default: None
49 | state:
50 | description: OS state
51 | required: false
52 | default: 'present'
53 | choices: ['present', 'absent']
54 | foreman_host:
55 | description: Hostname or IP address of Foreman system
56 | required: false
57 | default: 127.0.0.1
58 | foreman_port:
59 | description: Port of Foreman API
60 | required: false
61 | default: 443
62 | foreman_user:
63 | description: Username to be used to authenticate on Foreman
64 | required: true
65 | foreman_pass:
66 | description: Password to be used to authenticate user on Foreman
67 | required: true
68 | foreman_ssl:
69 | description: Enable SSL when connecting to Foreman API
70 | required: false
71 | default: true
72 | notes:
73 | - Requires the python-foreman package to be installed. See https://github.com/Nosmoht/python-foreman.
74 | version_added: "2.0"
75 | author: "Thomas Krahn (@nosmoht)"
76 | '''
77 |
78 | EXAMPLES = '''
79 | - name: Ensure CoreOS 607.0.0
80 | foreman_operatingsystem:
81 | name: CoreOS 607.0.0
82 | architectures:
83 | - x86_64
84 | description: CoreOS Current stable
85 | media:
86 | - CoreOS mirror
87 | major: 607
88 | minor: 0.0
89 | ptables:
90 | - CoreOS default fake
91 | state: present
92 | foreman_host: 127.0.0.1
93 | foreman_port: 443
94 | foreman_user: admin
95 | foreman_pass: secret
96 | '''
97 |
98 | try:
99 | from foreman.foreman import *
100 |
101 | foremanclient_found = True
102 | except ImportError:
103 | foremanclient_found = False
104 |
105 | try:
106 | from ansible.module_utils.foreman_utils import *
107 |
108 | has_import_error = False
109 | except ImportError as e:
110 | has_import_error = True
111 | import_error_msg = str(e)
112 |
113 |
114 | def oses_equal(data, os, comparable_keys, comparable_arrays=[]):
115 | if not all(data.get(key, None) == os.get(key, None) for key in comparable_keys):
116 | return False
117 | if not all(equal_dict_lists(l1=data.get(key, []), l2=os.get(key, [])) for key in comparable_arrays):
118 | return False
119 | if not organizations_equal(data, os):
120 | return False
121 | if not locations_equal(data, os):
122 | return False
123 | return True
124 |
125 |
126 | def get_resources(resource_type, resource_specs, theforeman, module):
127 | result = []
128 | for item in resource_specs:
129 | search_data = dict()
130 | if isinstance(item, dict):
131 | for key in item:
132 | search_data[key] = item[key]
133 | else:
134 | search_data['name'] = item
135 | try:
136 | resource = theforeman.search_resource(resource_type=resource_type, data=search_data)
137 | if not resource:
138 | module.fail_json(
139 | msg='Could not find resource type {resource_type} defined as {spec}'.format(
140 | resource_type=resource_type,
141 | spec=item))
142 | result.append(resource)
143 | except ForemanError as e:
144 | module.fail_json(msg='Could not search resource type {resource_type} defined as {spec}: {error}'.format(
145 | resource_type=resource_type, spec=item, error=e.message))
146 | return result
147 |
148 |
149 | def ensure(module):
150 | comparable_keys = ['description', 'family', 'major', 'minor', 'release_name']
151 | comparable_arrays = ['architectures']
152 | name = module.params['name']
153 | state = module.params['state']
154 |
155 | theforeman = init_foreman_client(module)
156 |
157 | data = dict(name=name)
158 | data['major'] = module.params['major']
159 | if module.params['minor']:
160 | data['minor'] = module.params['minor']
161 |
162 | try:
163 | os = theforeman.search_operatingsystem(data=data)
164 | if os:
165 | os = theforeman.get_operatingsystem(id=os.get('id'))
166 | except ForemanError as e:
167 | module.fail_json(msg='Could not get operatingsystem: {0}'.format(e.message))
168 |
169 | if state == 'absent':
170 | if os:
171 | try:
172 | os = theforeman.delete_operatingsystem(id=os.get('id'))
173 | return True, os
174 | except ForemanError as e:
175 | module.fail_json(msg='Could not delete operatingsystem: {0}'.format(e.message))
176 |
177 | return False, os
178 |
179 | data['architectures'] = get_resources(resource_type='architectures', resource_specs=module.params['architectures'],
180 | theforeman=theforeman, module=module)
181 | data['description'] = module.params['description']
182 | data['family'] = module.params['family']
183 | data['minor'] = module.params['minor']
184 | if module.params['media']:
185 | data['media'] = get_resources(resource_type='media', resource_specs=module.params['media'],
186 | theforeman=theforeman, module=module)
187 | comparable_arrays.append('media')
188 | if module.params['ptables']:
189 | data['ptables'] = get_resources(resource_type='ptables', resource_specs=module.params['ptables'],
190 | theforeman=theforeman, module=module)
191 | comparable_arrays.append('ptables')
192 | data['release_name'] = module.params['release_name']
193 |
194 | if not os:
195 | try:
196 | os = theforeman.create_operatingsystem(data=data)
197 | return True, os
198 | except ForemanError as e:
199 | module.fail_json(msg='Could not create operatingsystem: {0}'.format(e.message))
200 |
201 | if not oses_equal(data, os, comparable_keys, comparable_arrays):
202 | try:
203 | os = theforeman.update_operatingsystem(id=os.get('id'), data=data)
204 | return True, os
205 | except ForemanError as e:
206 | module.fail_json(msg='Could not update operatingsystem: {0}'.format(e.message))
207 |
208 | return False, os
209 |
210 |
211 | def main():
212 | module = AnsibleModule(
213 | argument_spec=dict(
214 | architectures=dict(type='list', required=False),
215 | description=dict(type='str', required=False),
216 | family=dict(type='str', required=False),
217 | major=dict(type='str', required=False),
218 | media=dict(type='list', required=False),
219 | minor=dict(type='str', required=False),
220 | name=dict(type='str', required=True),
221 | ptables=dict(type='list', required=False),
222 | release_name=dict(type='str', required=False),
223 | state=dict(type='str', default='present', choices=['present', 'absent']),
224 | foreman_host=dict(type='str', default='127.0.0.1'),
225 | foreman_port=dict(type='str', default='443'),
226 | foreman_user=dict(type='str', required=True),
227 | foreman_pass=dict(type='str', required=True, no_log=True),
228 | foreman_ssl=dict(type='bool', default=True)
229 | ),
230 | )
231 |
232 | if not foremanclient_found:
233 | module.fail_json(msg='python-foreman module is required. See https://github.com/Nosmoht/python-foreman.')
234 |
235 | changed, os = ensure(module)
236 | module.exit_json(changed=changed, operatingsystem=os)
237 |
238 |
239 | from ansible.module_utils.basic import *
240 |
241 | if __name__ == '__main__':
242 | main()
243 |
--------------------------------------------------------------------------------
/foreman_organization.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding: utf-8 -*-
3 | #
4 | # Ansible module to manage Foreman organization resources.
5 | #
6 | # This module is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This software is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with this software. If not, see .
18 |
19 | DOCUMENTATION = '''
20 | ---
21 | module: foreman_organization
22 | short_description: Manage Foreman organization resources using Foreman API v2
23 | description:
24 | - Create and delete Foreman organization resources using Foreman API v2
25 | options:
26 | name:
27 | description: Organization name
28 | required: true
29 | state:
30 | description: Organization state
31 | required: false
32 | default: present
33 | choices: ["present", "absent"]
34 | foreman_host:
35 | description: Hostname or IP address of Foreman system
36 | required: false
37 | default: 127.0.0.1
38 | foreman_port:
39 | description: Port of Foreman API
40 | required: false
41 | default: 443
42 | foreman_user:
43 | description: Username to be used to authenticate on Foreman
44 | required: true
45 | foreman_pass:
46 | description: Password to be used to authenticate user on Foreman
47 | required: true
48 | foreman_ssl:
49 | description: Enable SSL when connecting to Foreman API
50 | required: false
51 | default: true
52 | notes:
53 | - Requires the python-foreman package to be installed. See https://github.com/Nosmoht/python-foreman.
54 | version_added: "2.0"
55 | author: "Thomas Krahn (@nosmoht)"
56 | '''
57 |
58 | try:
59 | from foreman.foreman import *
60 | except ImportError:
61 | foremanclient_found = False
62 | else:
63 | foremanclient_found = True
64 |
65 |
66 | def ensure(module):
67 | name = module.params['name']
68 | state = module.params['state']
69 |
70 | foreman_host = module.params['foreman_host']
71 | foreman_port = module.params['foreman_port']
72 | foreman_user = module.params['foreman_user']
73 | foreman_pass = module.params['foreman_pass']
74 | foreman_ssl = module.params['foreman_ssl']
75 |
76 | theforeman = Foreman(hostname=foreman_host,
77 | port=foreman_port,
78 | username=foreman_user,
79 | password=foreman_pass,
80 | ssl=foreman_ssl)
81 |
82 | data = {'name': name}
83 |
84 | try:
85 | organization = theforeman.search_organization(data=data)
86 | except ForemanError as e:
87 | module.fail_json(msg='Could not get organization: {0}'.format(e.message))
88 |
89 | if not organization and state == 'present':
90 | try:
91 | theforeman.create_organization(data=data)
92 | return True
93 | except ForemanError as e:
94 | module.fail_json(msg='Could not create organization: {0}'.format(e.message))
95 |
96 | if organization and state == 'absent':
97 | try:
98 | theforeman.delete_organization(id=organization.get('id'))
99 | return True
100 | except ForemanError as e:
101 | module.fail_json('Could not delete organization: {0}'.format(e.message))
102 |
103 | return False
104 |
105 |
106 | def main():
107 | module = AnsibleModule(
108 | argument_spec=dict(
109 | name=dict(type='str', required=True),
110 | state=dict(type='str', default='present', choices=['present', 'absent']),
111 | foreman_host=dict(type='str', default='127.0.0.1'),
112 | foreman_port=dict(type='str', default='443'),
113 | foreman_user=dict(type='str', required=True),
114 | foreman_pass=dict(type='str', required=True, no_log=True),
115 | foreman_ssl=dict(type='bool', default=True)
116 | ),
117 | )
118 |
119 | if not foremanclient_found:
120 | module.fail_json(msg='python-foreman module is required. See https://github.com/Nosmoht/python-foreman.')
121 |
122 | changed = ensure(module)
123 | module.exit_json(changed=changed, name=module.params['name'])
124 |
125 |
126 | from ansible.module_utils.basic import *
127 |
128 | if __name__ == '__main__':
129 | main()
130 |
--------------------------------------------------------------------------------
/foreman_os_default_template.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding: utf-8 -*-
3 | #
4 | # Ansible module to manage Foreman operating system default template resources.
5 | #
6 | # This module is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This software is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with this software. If not, see .
18 |
19 | DOCUMENTATION = '''
20 | ---
21 | module: foreman_os_default_template
22 | short_description: Manage Foreman Operatingsystem default templates using Foreman API v2
23 | description:
24 | - Create,update and delete Foreman Operatingsystem default templates using Foreman API v2
25 | options:
26 | operatingsystem:
27 | description: Operatingsystem name
28 | required: true
29 | config_template:
30 | description: Config Template name
31 | required: true
32 | template_kind:
33 | description: Template kind
34 | required: true
35 | state:
36 | description: OS Default template state
37 | required: false
38 | default: 'present'
39 | choices: ['present', 'absent']
40 | foreman_host:
41 | description: Hostname or IP address of Foreman system
42 | required: false
43 | default: 127.0.0.1
44 | foreman_port:
45 | description: Port of Foreman API
46 | required: false
47 | default: 443
48 | foreman_user:
49 | description: Username to be used to authenticate on Foreman
50 | required: true
51 | foreman_pass:
52 | description: Password to be used to authenticate user on Foreman
53 | required: true
54 | foreman_ssl:
55 | description: Enable SSL when connecting to Foreman API
56 | required: false
57 | default: true
58 | notes:
59 | - Requires the python-foreman package to be installed. See https://github.com/Nosmoht/python-foreman.
60 | version_added: "2.0"
61 | author: "Thomas Krahn (@nosmoht)"
62 | '''
63 |
64 | EXAMPLES = '''
65 | - name: Ensure OS Default Template
66 | foreman_os_default_template:
67 | operatingsystem: CoreOS
68 | config_template: CoreOS PXELinux
69 | template_kind: PXELinux
70 | state: present
71 | foreman_user: admin
72 | foreman_pass: secret
73 | foreman_host: foreman.example.com
74 | foreman_port: 443
75 | '''
76 |
77 | try:
78 | from foreman.foreman import *
79 | except ImportError:
80 | foremanclient_found = False
81 | else:
82 | foremanclient_found = True
83 |
84 |
85 | def ensure():
86 | os_name = module.params['operatingsystem']
87 | config_template_name = module.params['config_template']
88 | template_kind_name = module.params['template_kind']
89 | state = module.params['state']
90 |
91 | try:
92 | os = theforeman.search_operatingsystem(data=dict(name=os_name))
93 | except ForemanError as e:
94 | module.fail_json(msg='Could not search operatingsystem: {0}'.format(e.message))
95 |
96 | if not os:
97 | module.fail_json(msg='Operatingsystem {os_name} not found'.format(os_name=os_name))
98 |
99 | try:
100 | config_templates = theforeman.get_config_templates()
101 | except:
102 | module.fail_json(msg='Could not get config templates: {0}'.format(e.message))
103 |
104 | config_template = None
105 | for item in config_templates:
106 | if item.get('name') == config_template_name and item.get('template_kind_name') == template_kind_name:
107 | config_template = item
108 | break
109 |
110 | if not config_template:
111 | module.fail_json(msg='Could not find config template {config_template} of kind {template_kind}'.format(
112 | config_template_name=config_template_name, template_kind=template_kind_name))
113 |
114 | try:
115 | os_default_templates = theforeman.get_operatingsystem_default_templates(id=os.get('id'))
116 | except ForemanError as e:
117 | module.fail_json(msg='Could not get operatingsystem default templates: {0}'.format(e.message))
118 |
119 | os_default_template = None
120 | for item in os_default_templates:
121 | if (item.get('config_template_id') == config_template.get('id')) and (
122 | item.get('template_kind_id') == config_template.get('template_kind_id')):
123 | os_default_template = item
124 | break
125 |
126 | if state == 'absent':
127 | if os_default_template:
128 | try:
129 | os_default_template = theforeman.delete_operatingsystem_default_template(id=os.get('id'),
130 | template_id=os_default_template.get(
131 | 'id'))
132 | except:
133 | module.fail_json(msg='Could not delete operatingsystem default template: {0}'.format(e.message))
134 | return True, os_default_template
135 | return False, os_default_template
136 |
137 | if not os_default_template:
138 | try:
139 | os_default_template = theforeman.create_operatingsystem_default_template(id=os.get('id'), data=dict(
140 | config_template_id=config_template.get('id'), template_kind_id=config_template.get('template_kind_id')))
141 | except ForemanError as e:
142 | module.fail_json(msg='Could not create operatingsystem default template: {0}'.format(e.message))
143 | return True, os_default_template
144 |
145 | return False, os_default_template
146 |
147 |
148 | def main():
149 | global module
150 | global theforeman
151 |
152 | module = AnsibleModule(
153 | argument_spec=dict(
154 | operatingsystem=dict(type='str', required=True),
155 | config_template=dict(type='str', required=True),
156 | template_kind=dict(type='str', required=True),
157 | state=dict(type='str', default='present', choices=['present', 'absent']),
158 | foreman_host=dict(type='str', default='127.0.0.1'),
159 | foreman_port=dict(type='str', default='443'),
160 | foreman_user=dict(type='str', required=True),
161 | foreman_pass=dict(type='str', required=True, no_log=True),
162 | foreman_ssl=dict(type='bool', default=True)
163 | ),
164 | )
165 |
166 | if not foremanclient_found:
167 | module.fail_json(msg='python-foreman module is required. See https://github.com/Nosmoht/python-foreman.')
168 |
169 | foreman_host = module.params['foreman_host']
170 | foreman_port = module.params['foreman_port']
171 | foreman_user = module.params['foreman_user']
172 | foreman_pass = module.params['foreman_pass']
173 | foreman_ssl = module.params['foreman_ssl']
174 |
175 | theforeman = Foreman(hostname=foreman_host,
176 | port=foreman_port,
177 | username=foreman_user,
178 | password=foreman_pass,
179 | ssl=foreman_ssl)
180 |
181 | changed, os_default_template = ensure()
182 | module.exit_json(changed=changed, os_default_template=os_default_template)
183 |
184 |
185 | from ansible.module_utils.basic import *
186 |
187 | if __name__ == '__main__':
188 | main()
189 |
--------------------------------------------------------------------------------
/foreman_ptable.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding: utf-8 -*-
3 | #
4 | # Ansible module to manage Foreman partition table resources.
5 | #
6 | # This module is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This software is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with this software. If not, see .
18 |
19 | DOCUMENTATION = '''
20 | ---
21 | module: foreman_ptable
22 | short_description: Manage Foreman Partition Tables using Foreman API v2
23 | description:
24 | - Create, update and delete Foreman Partition Tables using Foreman API v2
25 | options:
26 | name:
27 | description:
28 | - Partition Table name
29 | required: true
30 | layout:
31 | description:
32 | - Partition Table layout
33 | required: false
34 | os_family:
35 | description:
36 | - OS family
37 | required: false
38 | operatingsystems:
39 | description:
40 | - List of Operating systems
41 | required: False
42 | default: None
43 | organizations:
44 | description:
45 | - List of organization the ptable should be assigned to
46 | required: false
47 | locations:
48 | description:
49 | - List of locations the ptable should be assigned to
50 | required: false
51 | state:
52 | description:
53 | - Partition Table state
54 | required: false
55 | default: 'present'
56 | choices: ['present', 'absent']
57 | foreman_host:
58 | description:
59 | - Hostname or IP address of Foreman system
60 | required: false
61 | default: 127.0.0.1
62 | foreman_port:
63 | description:
64 | - Port of Foreman API
65 | required: false
66 | default: 443
67 | foreman_user:
68 | description:
69 | - Username to be used to authenticate on Foreman
70 | required: true
71 | foreman_pass:
72 | description:
73 | - Password to be used to authenticate user on Foreman
74 | required: true
75 | foreman_ssl:
76 | description: Enable SSL when connecting to Foreman API
77 | required: false
78 | default: true
79 | notes:
80 | - Requires the python-foreman package to be installed. See https://github.com/Nosmoht/python-foreman.
81 | version_added: "2.0"
82 | author: "Thomas Krahn (@nosmoht)"
83 | '''
84 |
85 | EXAMPLES = '''
86 | - name: Ensure Partition Table
87 | foreman_ptable:
88 | name: FreeBSD
89 | layout: 'some layout'
90 | state: present
91 | foreman_user: admin
92 | foreman_pass: secret
93 | foreman_host: foreman.example.com
94 | foreman_port: 443
95 | '''
96 |
97 | try:
98 | from foreman.foreman import *
99 | except ImportError:
100 | foremanclient_found = False
101 | else:
102 | foremanclient_found = True
103 |
104 | try:
105 | from ansible.module_utils.foreman_utils import *
106 |
107 | has_import_error = False
108 | except ImportError as e:
109 | has_import_error = True
110 | import_error_msg = str(e)
111 |
112 | def ptables_equal(data, ptable):
113 | comparable_keys = set(data.keys()).intersection(set(
114 | ['layout', 'os_family']))
115 | if not all(data.get(key, None) == ptable.get(key, None) for key in comparable_keys):
116 | return False
117 | if not operatingsystems_equal(data, ptable):
118 | return False
119 | if not organizations_equal(data, ptable):
120 | return False
121 | if not locations_equal(data, ptable):
122 | return False
123 | return True
124 |
125 | def ensure():
126 | name = module.params['name']
127 | layout = module.params['layout']
128 | state = module.params['state']
129 | os_family = module.params['os_family']
130 | operating_systems = module.params['operating_systems']
131 | organizations = module.params['organizations']
132 | locations = module.params['locations']
133 |
134 | theforeman = init_foreman_client(module)
135 |
136 | data = dict(name=name)
137 |
138 | try:
139 | ptable = theforeman.search_partition_table(data=data)
140 | except ForemanError as e:
141 | module.fail_json(msg='Could not get partition table: {0}'.format(e.message))
142 |
143 | if layout:
144 | data['layout'] = layout
145 | if os_family:
146 | data['os_family'] = os_family
147 | if organizations is not None:
148 | data['organization_ids'] = get_organization_ids(module, theforeman, organizations)
149 | if locations is not None:
150 | data['location_ids'] = get_location_ids(module, theforeman, locations)
151 | if operating_systems is not None:
152 | data['operatingsystem_ids'] = get_operatingsystem_ids(module, theforeman, operating_systems)
153 |
154 | if not ptable and state == 'present':
155 | try:
156 | ptable = theforeman.create_partition_table(data)
157 | except ForemanError as e:
158 | module.fail_json(msg='Could not create partition table: {0}'.format(e.message))
159 | return True, ptable
160 |
161 | if ptable and state == 'absent':
162 | try:
163 | ptable = theforeman.delete_partition_table(id=ptable.get('id'))
164 | except ForemanError as e:
165 | module.fail_json(msg='Could not delete partition table: {0}'.format(e.message))
166 | return True, ptable
167 |
168 | if ptable and state == 'present':
169 | try:
170 | ptable = theforeman.get_partition_table(id=ptable.get('id'))
171 | except ForemanError as e:
172 | module.fail_json(msg='Could not get partition table to update: {0}'.format(e.message))
173 | if not ptables_equal(data, ptable):
174 | try:
175 | ptable = theforeman.update_partition_table(id=ptable.get('id'), data=data)
176 | except ForemanError as e:
177 | module.fail_json(msg='Could not update partition table: {0}'.format(e.message))
178 | return True, ptable
179 |
180 | return False, ptable
181 |
182 |
183 | def main():
184 | global module
185 | global theforeman
186 |
187 | module = AnsibleModule(
188 | argument_spec=dict(
189 | name=dict(type='str', required=True),
190 | layout=dict(type='str', required=False),
191 | os_family=dict(type='str', required=False),
192 | operating_systems=dict(type='list', required=False),
193 | organizations=dict(type='list', required=False),
194 | locations=dict(type='list', required=False),
195 | state=dict(type='str', default='present', choices=['present', 'absent']),
196 | foreman_host=dict(type='str', default='127.0.0.1'),
197 | foreman_port=dict(type='str', default='443'),
198 | foreman_user=dict(type='str', required=True),
199 | foreman_pass=dict(type='str', required=True, no_log=True),
200 | foreman_ssl=dict(type='bool', default=True)
201 | ),
202 | )
203 |
204 | if not foremanclient_found:
205 | module.fail_json(msg='python-foreman module is required. See https://github.com/Nosmoht/python-foreman.')
206 | if has_import_error:
207 | module.fail_json(msg=import_error_msg)
208 |
209 | changed, ptable = ensure()
210 | module.exit_json(changed=changed, ptable=ptable)
211 |
212 |
213 | from ansible.module_utils.basic import *
214 |
215 | if __name__ == '__main__':
216 | main()
217 |
--------------------------------------------------------------------------------
/foreman_realm.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding: utf-8 -*-
3 | #
4 | # Ansible module to manage Foreman realm resources.
5 | #
6 | # This module is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This software is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with this software. If not, see .
18 |
19 | DOCUMENTATION = '''
20 | ---
21 | module: foreman_realm
22 | short_description: Manage Foreman Realm using Foreman API v2
23 | description:
24 | - Create, update and delete Foreman Realms using Foreman API v2
25 | options:
26 | name:
27 | description: Realm name
28 | required: true
29 | realm_proxy:
30 | description: Realm smart proxy to use
31 | required: true
32 | realm_type:
33 | description: Realm type (e.g FreeIPA)
34 | required: true
35 | state:
36 | description: Realm state
37 | required: false
38 | default: 'present'
39 | choices: ['present', 'absent']
40 | foreman_host:
41 | description: Hostname or IP address of Foreman system
42 | required: false
43 | default: 127.0.0.1
44 | foreman_port:
45 | description: Port of Foreman API
46 | required: false
47 | default: 443
48 | foreman_user:
49 | description: Username to be used to authenticate on Foreman
50 | required: true
51 | foreman_pass:
52 | description: Password to be used to authenticate user on Foreman
53 | required: true
54 | foreman_ssl:
55 | description: Enable SSL when connecting to Foreman API
56 | required: false
57 | default: true
58 | notes:
59 | - Requires the python-foreman package to be installed. See https://github.com/Nosmoht/python-foreman.
60 | version_added: "2.0"
61 | author: "Thomas Krahn (@nosmoht)"
62 | '''
63 |
64 | EXAMPLES = '''
65 | - name: Ensure Realm
66 | foreman_realm:
67 | name: MyRealm
68 | realm_proxy: http://localhost:3000
69 | realm_type: FreeIPA
70 | state: present
71 | foreman_host: foreman.example.com
72 | foreman_port: 443
73 | foreman_user: admin
74 | foreman_pass: secret
75 | '''
76 |
77 | try:
78 | from foreman.foreman import *
79 |
80 | foremanclient_found = True
81 | except ImportError:
82 | foremanclient_found = False
83 |
84 |
85 | def get_resources(resource_type, resource_specs):
86 | result = []
87 | for item in resource_specs:
88 | search_data = dict()
89 | if isinstance(item, dict):
90 | for key in item:
91 | search_data[key] = item[key]
92 | else:
93 | search_data['name'] = item
94 | try:
95 | resource = theforeman.search_resource(resource_type=resource_type, data=search_data)
96 | if not resource:
97 | module.fail_json(
98 | msg='Could not find resource type {resource_type} defined as {spec}'.format(
99 | resource_type=resource_type,
100 | spec=item))
101 | result.append(resource)
102 | except ForemanError as e:
103 | module.fail_json(msg='Could not search resource type {resource_type} defined as {spec}: {error}'.format(
104 | resource_type=resource_type, spec=item, error=e.message))
105 | return result
106 |
107 |
108 | def ensure(module):
109 | global theforeman
110 |
111 | name = module.params['name']
112 | realm_proxy = module.params['realm_proxy']
113 | realm_type = module.params['realm_type']
114 | state = module.params['state']
115 |
116 | foreman_host = module.params['foreman_host']
117 | foreman_port = module.params['foreman_port']
118 | foreman_user = module.params['foreman_user']
119 | foreman_pass = module.params['foreman_pass']
120 | foreman_ssl = module.params['foreman_ssl']
121 |
122 | theforeman = Foreman(hostname=foreman_host,
123 | port=foreman_port,
124 | username=foreman_user,
125 | password=foreman_pass,
126 | ssl=foreman_ssl)
127 |
128 | data = {'name': name}
129 | try:
130 | realm = theforeman.search_realm(data=data)
131 | except ForemanError as e:
132 | module.fail_json(msg='Could not get realm: {0}'.format(e.message))
133 |
134 | data['realm_type'] = realm_type
135 | data['realm_proxy_id'] = get_resources(resource_type='smart_proxies', resource_specs=[realm_proxy])[0].get('id')
136 | if not realm and state == 'present':
137 | try:
138 | realm = theforeman.create_realm(data=data)
139 | return True, realm
140 | except ForemanError as e:
141 | module.fail_json(msg='Could not create realm: {0}'.format(e.message))
142 |
143 | if realm:
144 | if state == 'absent':
145 | try:
146 | realm = theforeman.delete_realm(id=realm.get('id'))
147 | return True, realm
148 | except ForemanError as e:
149 | module.fail_json(msg='Could not delete realm: {0}'.format(e.message))
150 |
151 | elif not all(data[key] == realm[key] for key in data):
152 | try:
153 | realm = theforeman.update_realm(id=realm.get('id'), data=data)
154 | return True, realm
155 | except ForemanError as e:
156 | module.fail_json(msg='Could not update realm: {0}'.format(e.message))
157 |
158 | return False, realm
159 |
160 |
161 | def main():
162 | global module
163 |
164 | module = AnsibleModule(
165 | argument_spec=dict(
166 | name=dict(type='str', required=True),
167 | realm_proxy=dict(type='str', required=True),
168 | realm_type=dict(type='str', required=True),
169 | state=dict(type='str', default='present', choices=['present', 'absent']),
170 | foreman_host=dict(type='str', default='127.0.0.1'),
171 | foreman_port=dict(type='str', default='443'),
172 | foreman_user=dict(type='str', required=True),
173 | foreman_pass=dict(type='str', required=True, no_log=True),
174 | foreman_ssl=dict(type='bool', default=True)
175 | ),
176 | )
177 |
178 | if not foremanclient_found:
179 | module.fail_json(msg='python-foreman module is required. See https://github.com/Nosmoht/python-foreman.')
180 |
181 | changed, realm = ensure(module)
182 | module.exit_json(changed=changed, realm=realm)
183 |
184 |
185 | from ansible.module_utils.basic import *
186 |
187 | if __name__ == '__main__':
188 | main()
189 |
--------------------------------------------------------------------------------
/foreman_role.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding: utf-8 -*-
3 | #
4 | # Ansible module to manage Foreman role resources.
5 | #
6 | # This module is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This software is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with this software. If not, see .
18 |
19 | DOCUMENTATION = '''
20 | ---
21 | module: foreman_role
22 | short_description: Manage Foreman Role using Foreman API v2
23 | description:
24 | - Create, update and delete Foreman Role using Foreman API v2
25 | options:
26 | name:
27 | description: Role name
28 | required: false
29 | default: None
30 | state:
31 | description: Role state
32 | required: false
33 | default: 'present'
34 | choices: ['present', 'absent']
35 | foreman_host:
36 | description: Hostname or IP address of Foreman system
37 | required: false
38 | default: 127.0.0.1
39 | foreman_port:
40 | description: Port of Foreman API
41 | required: false
42 | default: 443
43 | foreman_user:
44 | description: Username to be used to authenticate on Foreman
45 | required: true
46 | foreman_pass:
47 | description: Password to be used to authenticate user on Foreman
48 | required: true
49 | foreman_ssl:
50 | description: Enable SSL when connecting to Foreman API
51 | required: false
52 | default: true
53 | notes:
54 | - Requires the python-foreman package to be installed. See https://github.com/Nosmoht/python-foreman.
55 | version_added: "2.0"
56 | author: "Thomas Krahn (@nosmoht)"
57 | '''
58 |
59 | EXAMPLES = '''
60 | - name: Ensure Role
61 | foreman_role:
62 | name: MyRole
63 | state: present
64 | foreman_host: foreman.example.com
65 | foreman_port: 443
66 | foreman_user: admin
67 | foreman_pass: secret
68 | '''
69 |
70 | try:
71 | from foreman.foreman import *
72 |
73 | foremanclient_found = True
74 | except ImportError:
75 | foremanclient_found = False
76 |
77 |
78 | def ensure(module):
79 | name = module.params['name']
80 | state = module.params['state']
81 |
82 | foreman_host = module.params['foreman_host']
83 | foreman_port = module.params['foreman_port']
84 | foreman_user = module.params['foreman_user']
85 | foreman_pass = module.params['foreman_pass']
86 | foreman_ssl = module.params['foreman_ssl']
87 |
88 | theforeman = Foreman(hostname=foreman_host,
89 | port=foreman_port,
90 | username=foreman_user,
91 | password=foreman_pass,
92 | ssl=foreman_ssl)
93 |
94 | data = {'name': name}
95 |
96 | try:
97 | role = theforeman.search_role(data=data)
98 | except ForemanError as e:
99 | module.fail_json(msg='Could not get role: {0}'.format(e.message))
100 |
101 | if not role and state == 'present':
102 | try:
103 | role = theforeman.create_role(data=data)
104 | return True, role
105 | except ForemanError as e:
106 | module.fail_json(msg='Could not create role: {0}'.format(e.message))
107 |
108 | if role:
109 | if state == 'absent':
110 | try:
111 | role = theforeman.delete_role(id=role.get('id'))
112 | return True, role
113 | except ForemanError as e:
114 | module.fail_json(msg='Could not delete role: {0}'.format(e.message))
115 |
116 | return False, role
117 |
118 |
119 | def main():
120 | module = AnsibleModule(
121 | argument_spec=dict(
122 | name=dict(type='str', required=True),
123 | state=dict(type='str', default='present', choices=['present', 'absent']),
124 | foreman_host=dict(type='str', default='127.0.0.1'),
125 | foreman_port=dict(type='str', default='443'),
126 | foreman_user=dict(type='str', required=True),
127 | foreman_pass=dict(type='str', required=True, no_log=True),
128 | foreman_ssl=dict(type='bool', default=True)
129 | ),
130 | )
131 |
132 | if not foremanclient_found:
133 | module.fail_json(msg='python-foreman module is required. See https://github.com/Nosmoht/python-foreman.')
134 |
135 | changed, role = ensure(module)
136 | module.exit_json(changed=changed, role=role)
137 |
138 |
139 | from ansible.module_utils.basic import *
140 |
141 | if __name__ == '__main__':
142 | main()
143 |
--------------------------------------------------------------------------------
/foreman_setting.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding: utf-8 -*-
3 | #
4 | # Ansible module to manage Foreman settings.
5 | #
6 | # This module is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This software is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with this software. If not, see .
18 |
19 | DOCUMENTATION = '''
20 | ---
21 | module: foreman_setting
22 | short_description: Manage Foreman setting using Foreman API v2
23 | description:
24 | - Update Foreman settings using Foreman API v2
25 | options:
26 | name:
27 | description: Setting name
28 | required: true
29 | value:
30 | description: setting value
31 | required: false
32 | foreman_host:
33 | description: Hostname or IP address of Foreman system
34 | required: false
35 | default: 127.0.0.1
36 | foreman_port:
37 | description: Port of Foreman API
38 | required: false
39 | default: 443
40 | foreman_user:
41 | description: Username to be used to authenticate on Foreman
42 | required: true
43 | foreman_pass:
44 | description: Password to be used to authenticate user on Foreman
45 | required: true
46 | foreman_ssl:
47 | description: Enable SSL when connecting to Foreman API
48 | required: false
49 | default: true
50 | notes:
51 | - Requires the python-foreman package to be installed. See https://github.com/Nosmoht/python-foreman.
52 | version_added: "2.0"
53 | author: "Guido Günther "
54 | '''
55 |
56 | EXAMPLES = '''
57 | - name: Ensure Setting
58 | foreman_setting:
59 | name: outofsync_interval
60 | value: 10
61 | foreman_host: foreman.example.com
62 | foreman_port: 443
63 | foreman_user: admin
64 | foreman_pass: secret
65 | '''
66 |
67 | try:
68 | from foreman.foreman import *
69 | foremanclient_found = True
70 | except ImportError:
71 | foremanclient_found = False
72 |
73 |
74 | def update_setting(setting, data):
75 | try:
76 | setting = theforeman.update_setting(id=setting['id'], data=data)
77 | except ForemanError as e:
78 | module.fail_json(msg='Could not update setting: {0}'.format(e.message))
79 | return setting
80 |
81 |
82 | def fake_setting(setting, data):
83 | setting['value'] = data['value']
84 |
85 |
86 | def ensure(module):
87 | global theforeman
88 |
89 | name = module.params['name']
90 | value = module.params['value']
91 |
92 | foreman_host = module.params['foreman_host']
93 | foreman_port = module.params['foreman_port']
94 | foreman_user = module.params['foreman_user']
95 | foreman_pass = module.params['foreman_pass']
96 | foreman_ssl = module.params['foreman_ssl']
97 |
98 | theforeman = Foreman(hostname=foreman_host,
99 | port=foreman_port,
100 | username=foreman_user,
101 | password=foreman_pass,
102 | ssl=foreman_ssl)
103 |
104 | data = {'name': name}
105 | try:
106 | setting = theforeman.search_setting(data=data)
107 | except ForemanError as e:
108 | module.fail_json(msg='Could not get setting: {0}'.format(e.message))
109 |
110 | if not setting:
111 | module.fail_json(msg='Setting %s does not exist' % name)
112 |
113 | if isinstance(setting['value'], (bool, str, int)):
114 | data['value'] = type(setting['value'])(value)
115 | else:
116 | data['value'] = value
117 |
118 | if data['value'] != setting['value']:
119 | if module.check_mode:
120 | setting = fake_setting(setting, data)
121 | else:
122 | setting = update_setting(setting, data)
123 | return True, setting
124 | return False, setting
125 |
126 |
127 | def main():
128 | global module
129 |
130 | module = AnsibleModule(
131 | argument_spec=dict(
132 | name=dict(type='str', required=True),
133 | value=dict(type='str', required=True),
134 | foreman_host=dict(type='str', default='127.0.0.1'),
135 | foreman_port=dict(type='str', default='443'),
136 | foreman_user=dict(type='str', required=True),
137 | foreman_pass=dict(type='str', required=True, no_log=True),
138 | foreman_ssl=dict(type='bool', default=True)
139 | ),
140 | supports_check_mode=True,
141 | )
142 |
143 | if not foremanclient_found:
144 | module.fail_json(msg='python-foreman module is required. See https://github.com/Nosmoht/python-foreman.')
145 |
146 | changed, setting = ensure(module)
147 | module.exit_json(changed=changed, setting=setting)
148 |
149 | # import module snippets
150 | from ansible.module_utils.basic import *
151 |
152 | if __name__ == '__main__':
153 | main()
154 |
--------------------------------------------------------------------------------
/foreman_smart_proxy.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding: utf-8 -*-
3 | #
4 | # Ansible module to manage Foreman smart proxy resources.
5 | #
6 | # This module is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This software is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with this software. If not, see .
18 |
19 | DOCUMENTATION = '''
20 | ---
21 | module: foreman_smart_proxy
22 | short_description: Manage Foreman smart proxy resources using Foreman API v2
23 | description:
24 | - Create and delete Foreman smart proxy resources using Foreman API v2
25 | options:
26 | name:
27 | description: Smart proxy name
28 | required: true
29 | state:
30 | description: Smart proxy state
31 | required: false
32 | default: present
33 | choices: ["present", "absent"]
34 | url:
35 | description: Smart proxy URL
36 | required: false
37 | default: None
38 | locations: List of locations the smart_proxy should be assigned to
39 | required: false
40 | default: None
41 | organizations: List of organizations the smart_proxy should be assigned to
42 | required: false
43 | default: None
44 | foreman_host:
45 | description: Hostname or IP address of Foreman system
46 | required: false
47 | default: 127.0.0.1
48 | foreman_port:
49 | description: Port of Foreman API
50 | required: false
51 | default: 443
52 | foreman_user:
53 | description: Username to be used to authenticate on Foreman
54 | required: true
55 | foreman_pass:
56 | description: Password to be used to authenticate user on Foreman
57 | required: true
58 | foreman_ssl:
59 | description: Enable SSL when connecting to Foreman API
60 | required: false
61 | default: true
62 | notes:
63 | - Requires the python-foreman package to be installed. See https://github.com/Nosmoht/python-foreman.
64 | version_added: "2.0"
65 | author: "Thomas Krahn (@nosmoht)"
66 | '''
67 |
68 | try:
69 | from foreman.foreman import *
70 |
71 | foremanclient_found = True
72 | except ImportError:
73 | foremanclient_found = False
74 |
75 | try:
76 | from ansible.module_utils.foreman_utils import *
77 |
78 | has_import_error = False
79 | except ImportError as e:
80 | has_import_error = True
81 | import_error_msg = str(e)
82 |
83 |
84 | def smart_proxies_equal(data, smart_proxy):
85 | comparable_keys = set(data.keys()).intersection(set(['url']))
86 | if not all(data.get(key, None) == smart_proxy.get(key, None) for key in comparable_keys):
87 | return False
88 | if not organizations_equal(data, smart_proxy):
89 | return False
90 | if not locations_equal(data, smart_proxy):
91 | return False
92 | return True
93 |
94 |
95 | def ensure(module):
96 | name = module.params['name']
97 | url = module.params['url']
98 | state = module.params['state']
99 | organizations = module.params['organizations']
100 | locations = module.params['locations']
101 |
102 | theforeman = init_foreman_client(module)
103 |
104 | data = {'name': name}
105 |
106 | try:
107 | smart_proxy = theforeman.search_smart_proxy(data=data)
108 | if smart_proxy:
109 | smart_proxy = theforeman.get_smart_proxy(id=smart_proxy.get('id'))
110 | except ForemanError as e:
111 | module.fail_json(msg='Could not get smart proxy: {0}'.format(e.message))
112 |
113 | if organizations:
114 | data['organization_ids'] = get_organization_ids(module, theforeman, organizations)
115 |
116 | if locations:
117 | data['location_ids'] = get_location_ids(module, theforeman, locations)
118 |
119 | data['url'] = url
120 |
121 | if not smart_proxy and state == 'present':
122 | try:
123 | smart_proxy = theforeman.create_smart_proxy(data=data)
124 | return True, smart_proxy
125 | except ForemanError as e:
126 | module.fail_json(msg='Could not create smart proxy: {0}'.format(e.message))
127 |
128 | if smart_proxy:
129 | if state == 'absent':
130 | try:
131 | smart_proxy = theforeman.delete_smart_proxy(id=smart_proxy.get('id'))
132 | return True, smart_proxy
133 | except ForemanError as e:
134 | module.fail_json(msg='Could not delete smart proxy: {0}'.format(e.message))
135 |
136 | if not smart_proxies_equal(data, smart_proxy):
137 | try:
138 | smart_proxy = theforeman.update_smart_proxy(id=smart_proxy.get('id'), data=data)
139 | return True, smart_proxy
140 | except ForemanError as e:
141 | module.fail_json(msg='Could not update smart proxy: {0}'.format(e.message))
142 | return False, smart_proxy
143 |
144 |
145 | def main():
146 | module = AnsibleModule(
147 | argument_spec=dict(
148 | name=dict(type='str', required=True),
149 | url=dict(type='str', required=False),
150 | state=dict(type='str', default='present', choices=['present', 'absent']),
151 | organizations=dict(type='list', required=False),
152 | locations=dict(type='list', required=False),
153 | foreman_host=dict(type='str', default='127.0.0.1'),
154 | foreman_port=dict(type='str', default='443'),
155 | foreman_user=dict(type='str', required=True),
156 | foreman_pass=dict(type='str', required=True, no_log=True),
157 | foreman_ssl=dict(type='bool', default=True)
158 | ),
159 | )
160 |
161 | if not foremanclient_found:
162 | module.fail_json(msg='python-foreman module is required. See https://github.com/Nosmoht/python-foreman.')
163 |
164 | changed, smart_proxy = ensure(module)
165 | module.exit_json(changed=changed, smart_proxy=smart_proxy)
166 |
167 |
168 | from ansible.module_utils.basic import *
169 |
170 | if __name__ == '__main__':
171 | main()
172 |
--------------------------------------------------------------------------------
/foreman_subnet.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding: utf-8 -*-
3 | #
4 | # Ansible module to manage Foreman subnet resources.
5 | #
6 | # This module is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This software is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with this software. If not, see .
18 |
19 | DOCUMENTATION = '''
20 | ---
21 | module: foreman_architecture
22 | short_description: Manage Foreman Architectures using Foreman API v2
23 | description:
24 | - Create and delete Foreman Architectures using Foreman API v2
25 | options:
26 | name:
27 | description: Subnet name
28 | required: True
29 | network:
30 | description: Subnet network
31 | required: False
32 | default: None
33 | mask:
34 | description: Netmask for this subnet
35 | required: False
36 | default: None
37 | gateway:
38 | description: Gateway for this subnet
39 | required: False
40 | default: None
41 | dns_primary:
42 | description: Primary DNS for this subnet
43 | required: False
44 | default: None
45 | dns_secondary:
46 | description: Secondary DNS for this subnet
47 | required: False
48 | default: None
49 | domains:
50 | description: Domains in which this subnet is part
51 | required: False
52 | default: None
53 | ipam:
54 | description: Enable IP Address auto suggestion for this subnet
55 | required: False
56 | default: None
57 | choices: ['DHCP', 'Internal DB', 'Random DB', 'None']),
58 | boot_mode:
59 | description: Default boot mode for interfaces assigned to this subnet
60 | required: False
61 | default: 'DHCP'
62 | choices: ['DHCP', 'Static']),
63 | ip_from:
64 | description: Starting IP Address for IP auto suggestion
65 | required: False
66 | default: None
67 | ip_to:
68 | description: Ending IP Address for IP auto suggestion
69 | required: False
70 | default: None
71 | dhcp_proxy:
72 | description: DHCP smart proxy to use for this subnet
73 | required: False
74 | default: None
75 | dns_proxy:
76 | description: DNS smart proxy to use for this subnet
77 | required: False
78 | default: None
79 | discovery_proxy:
80 | description: Discovery smart proxy to use for this subnet (requires foreman discover plugin)
81 | required: False
82 | default: None
83 | tftp_proxy:
84 | description: TFTP smart proxy to use for this subnet
85 | required: False
86 | default: None
87 | state:
88 | description: State of subnet
89 | required: false
90 | default: present
91 | choices: ["present", "absent"]
92 | vlanid:
93 | description: VLAN ID for this subnet
94 | required: False
95 | default: None
96 | locations: List of locations the subnet should be assigned to
97 | required: false
98 | default: None
99 | organizations: List of organizations the subnet should be assigned to
100 | required: false
101 | default: None
102 | foreman_host:
103 | description: Hostname or IP address of Foreman system
104 | required: false
105 | default: 127.0.0.1
106 | foreman_port:
107 | description: Port of Foreman API
108 | required: false
109 | default: 443
110 | foreman_user:
111 | description: Username to be used to authenticate on Foreman
112 | required: true
113 | foreman_pass:
114 | description: Password to be used to authenticate user on Foreman
115 | required: true
116 | foreman_ssl:
117 | description: Enable SSL when connecting to Foreman API
118 | required: false
119 | default: true
120 | notes:
121 | - Requires the python-foreman package to be installed. See https://github.com/Nosmoht/python-foreman.
122 | version_added: "2.0"
123 | author: "Thomas Krahn (@nosmoht)"
124 | '''
125 |
126 | EXAMPLES = '''
127 | - name: Ensure Subnet
128 | foreman_subnet:
129 | name: MySubnet
130 | network: 192.168.123.0
131 | mask: 255.255.255.0
132 | dns_primary: 192.168.123.1
133 | dns_secondary: 192.168.123.2
134 | domains:
135 | - foo.example.com
136 | ipam: DHCP
137 | boot_mode: Static
138 | ip_from: 192.168.123.3
139 | ip_to: 192.168.123.253
140 | gateway: 192.168.123.254
141 | vlanid: 123
142 | state: present
143 | locations:
144 | - Tardis
145 | organizations:
146 | - Dalek Inc
147 | - Cybermen
148 | foreman_host: 127.0.0.1
149 | foreman_port: 443
150 | foreman_user: admin
151 | foreman_pass: secret
152 | '''
153 |
154 | try:
155 | from foreman.foreman import *
156 | except ImportError:
157 | foremanclient_found = False
158 | else:
159 | foremanclient_found = True
160 |
161 | try:
162 | from ansible.module_utils.foreman_utils import *
163 |
164 | has_import_error = False
165 | except ImportError as e:
166 | has_import_error = True
167 | import_error_msg = str(e)
168 |
169 |
170 | def domains_equal(data, subnet):
171 | data_domains = list(map(lambda d: d['name'], data['domains'])).sort()
172 | subnet_domains = list(map(lambda d: d['name'], subnet['domains'])).sort()
173 | if data_domains != subnet_domains:
174 | return False
175 | return True
176 |
177 |
178 | def subnets_equal(data, subnet):
179 | comparable_keys = ['name', 'dns_primary', 'dns_secondary', 'gateway', 'ipam', 'boot_mode', 'mask', 'network',
180 | 'vlanid', 'from', 'to', 'tftp_id', 'dns_id', 'dhcp_id', 'discovery_id']
181 | if not all(data.get(key, None) == subnet.get(key, None) for key in comparable_keys):
182 | return False
183 | if not domains_equal(data, subnet):
184 | return False
185 | if not organizations_equal(data, subnet):
186 | return False
187 | if not locations_equal(data, subnet):
188 | return False
189 | return True
190 |
191 |
192 | def get_resources(resource_type, resource_specs, theforeman):
193 | result = []
194 | for item in resource_specs:
195 | search_data = dict()
196 | if isinstance(item, dict):
197 | for key in item:
198 | search_data[key] = item[key]
199 | else:
200 | search_data['name'] = item
201 | try:
202 | resource = theforeman.search_resource(resource_type=resource_type, data=search_data)
203 | if not resource:
204 | module.fail_json(
205 | msg='Could not find resource type {resource_type} defined as {spec}'.format(
206 | resource_type=resource_type,
207 | spec=item))
208 | result.append(resource)
209 | except ForemanError as e:
210 | module.fail_json(msg='Could not search resource type {resource_type} defined as {spec}: {error}'.format(
211 | resource_type=resource_type, spec=item, error=e.message))
212 | return result
213 |
214 |
215 | def prepare_data(data, module, theforeman):
216 | for key in ['dns_primary', 'dns_secondary', 'gateway', 'ipam', 'boot_mode', 'mask', 'network',
217 | 'vlanid', 'domains']:
218 | if key in module.params:
219 | data[key] = module.params[key]
220 | if 'ip_from' in module.params:
221 | data['from'] = module.params['ip_from']
222 | if 'ip_to' in module.params:
223 | data['to'] = module.params['ip_to']
224 | if 'domains' in module.params and module.params['domains']:
225 | data['domains'] = get_resources(resource_type='domains', resource_specs=module.params['domains'],
226 | theforeman=theforeman)
227 | for proxy_type in ['dns', 'dhcp', 'tftp', 'discovery']:
228 | key = "{0}_proxy".format(proxy_type)
229 | if key in module.params:
230 | id_key = "{0}_id".format(proxy_type)
231 | if module.params[key]:
232 | data[id_key] = get_resources(resource_type='smart_proxies', resource_specs=[module.params[key]],
233 | theforeman=theforeman)[0].get('id')
234 | else:
235 | data[id_key] = None
236 | return data
237 |
238 |
239 | def ensure(module):
240 | name = module.params['name']
241 | state = module.params['state']
242 | locations = module.params['locations']
243 | organizations = module.params['organizations']
244 |
245 | theforeman = init_foreman_client(module)
246 |
247 | data = {'name': name}
248 |
249 | try:
250 | subnet = theforeman.search_subnet(data=data)
251 | if subnet:
252 | subnet = theforeman.get_subnet(id=subnet.get('id'))
253 | except ForemanError as e:
254 | module.fail_json(msg='Could not get subnet: {0}'.format(e.message))
255 |
256 | if organizations:
257 | data['organization_ids'] = get_organization_ids(module, theforeman, organizations)
258 |
259 | if locations:
260 | data['location_ids'] = get_location_ids(module, theforeman, locations)
261 |
262 | data = prepare_data(data, module, theforeman)
263 |
264 | if not subnet and state == 'present':
265 | try:
266 | subnet = theforeman.create_subnet(data=data)
267 | return True, subnet
268 | except ForemanError as e:
269 | module.fail_json(msg='Could not create subnet: {0}'.format(e.message))
270 |
271 | if subnet:
272 | if state == 'absent':
273 | try:
274 | subnet = theforeman.delete_subnet(id=subnet.get('id'))
275 | return True, subnet
276 | except ForemanError as e:
277 | module.fail_json(msg='Could not delete subnet: {0}'.format(e.message))
278 |
279 | if not subnets_equal(data, subnet):
280 | try:
281 | subnet = theforeman.update_subnet(id=subnet.get('id'), data=data)
282 | return True, subnet
283 | except ForemanError as e:
284 | module.fail_json(msg='Could not update subnet: {0}'.format(e.message))
285 |
286 | return False, subnet
287 |
288 |
289 | def main():
290 | global module
291 |
292 | module = AnsibleModule(
293 | argument_spec=dict(
294 | dhcp_proxy=dict(type='str', required=False),
295 | dns_proxy=dict(type='str', required=False),
296 | discovery_proxy=dict(type='str', required=False),
297 | dns_primary=dict(type='str', required=False),
298 | dns_secondary=dict(type='str', required=False),
299 | domains=dict(type='list', required=False),
300 | gateway=dict(type='str', required=False),
301 | name=dict(type='str', required=True),
302 | network=dict(type='str', required=False),
303 | mask=dict(type='str', required=False),
304 | ipam=dict(type='str', required=False, choices=['DHCP', 'Internal DB', 'Random DB', 'None']),
305 | boot_mode=dict(type='str', required=False, choices=['DHCP', 'Static'], default='DHCP'),
306 | ip_from=dict(type='str', required=False),
307 | ip_to=dict(type='str', required=False),
308 | state=dict(type='str', default='present', choices=['present', 'absent']),
309 | tftp_proxy=dict(type='str', required=False),
310 | vlanid=dict(type='str', default=None),
311 | locations=dict(type='list', required=False),
312 | organizations=dict(type='list', required=False),
313 | foreman_host=dict(type='str', default='127.0.0.1'),
314 | foreman_port=dict(type='str', default='443'),
315 | foreman_user=dict(type='str', required=True),
316 | foreman_pass=dict(type='str', required=True, no_log=True),
317 | foreman_ssl=dict(type='bool', default=True)
318 | ),
319 | )
320 |
321 | if not foremanclient_found:
322 | module.fail_json(msg='python-foreman module is required. See https://github.com/Nosmoht/python-foreman.')
323 |
324 | changed, subnet = ensure(module)
325 | module.exit_json(changed=changed, subnet=subnet)
326 |
327 |
328 | from ansible.module_utils.basic import *
329 |
330 | if __name__ == '__main__':
331 | main()
332 |
--------------------------------------------------------------------------------
/foreman_user.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding: utf-8 -*-
3 | #
4 | # Ansible module to manage Foreman user resources.
5 | #
6 | # This module is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This software is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with this software. If not, see .
18 |
19 | DOCUMENTATION = '''
20 | ---
21 | module: foreman_user
22 | short_description: Manage Foreman Users using Foreman API v2
23 | description:
24 | - Manage Foreman users using Foreman API v2
25 | options:
26 | admin:
27 | description: Is an admin account
28 | required: false
29 | default: False
30 | choices: [True, False]
31 | auth:
32 | description: Authorization method
33 | required: false
34 | default: 'Internal'
35 | login:
36 | description: Name of user
37 | required: true
38 | default: None
39 | aliases: ['name']
40 | firstname:
41 | description: User's firstname
42 | required: false
43 | default: None
44 | lastname:
45 | description: User's lastname
46 | required: false
47 | default: None
48 | mail:
49 | description: Mail address
50 | required: false
51 | default: None
52 | password:
53 | description: Password
54 | required: false
55 | default: None
56 | roles:
57 | description: Roles assigned to the user
58 | required: false
59 | default: None
60 | state:
61 | description: State of user
62 | required: false
63 | default: present
64 | choices: ["present", "absent"]
65 | foreman_host:
66 | description: Hostname or IP address of Foreman system
67 | required: false
68 | default: 127.0.0.1
69 | foreman_port:
70 | description: Port of Foreman API
71 | required: false
72 | default: 443
73 | foreman_user:
74 | description: Username to be used to authenticate on Foreman
75 | required: true
76 | foreman_pass:
77 | description: Password to be used to authenticate user on Foreman
78 | required: true
79 | foreman_ssl:
80 | description: Enable SSL when connecting to Foreman API
81 | required: false
82 | default: true
83 | notes:
84 | - Requires the python-foreman package to be installed. See https://github.com/Nosmoht/python-foreman.
85 | version_added: "2.0"
86 | author: "Thomas Krahn (@nosmoht)"
87 | '''
88 |
89 | EXAMPLES = '''
90 | - name: Ensure foo user is present
91 | foreman_user:
92 | name: foo
93 | state: present
94 | roles:
95 | - "Viewer"
96 | foreman_user: admin
97 | foreman_pass: secret
98 | '''
99 |
100 | try:
101 | from foreman.foreman import *
102 |
103 | foremanclient_found = True
104 | except ImportError:
105 | foremanclient_found = False
106 |
107 |
108 | def get_roles(module, theforeman, roles):
109 | result = list()
110 | for item in roles:
111 | search_data = dict()
112 | if isinstance(item, dict):
113 | search_data = item
114 | else:
115 | search_data['name'] = item
116 | try:
117 | role = theforeman.search_role(data=search_data)
118 | if not role:
119 | module.fail_json(msg='Could not find role {0}'.format(item))
120 | result.append(role)
121 | except ForemanError as e:
122 | module.fail_json(msg='Could not search role {0}: {1}'.format(item, e.message))
123 | return result
124 |
125 |
126 | def extract_key_value_from_dict_array(a, key):
127 | result = list()
128 | for d in a:
129 | result.append(d.get(key, None))
130 | return result
131 |
132 |
133 | def equal_roles(assigned_roles, defined_roles):
134 | ar = set(extract_key_value_from_dict_array(assigned_roles, 'name'))
135 | dr = set(extract_key_value_from_dict_array(defined_roles, 'name'))
136 | return ar.issubset(dr) and dr.issubset(ar)
137 |
138 |
139 | def ensure(module):
140 | login = module.params['login']
141 | state = module.params['state']
142 | roles = module.params['roles']
143 |
144 | foreman_host = module.params['foreman_host']
145 | foreman_port = module.params['foreman_port']
146 | foreman_user = module.params['foreman_user']
147 | foreman_pass = module.params['foreman_pass']
148 | foreman_ssl = module.params['foreman_ssl']
149 |
150 | user_options = ['admin', 'auth_source_name', 'firstname', 'lastname', 'mail']
151 |
152 | theforeman = Foreman(hostname=foreman_host,
153 | port=foreman_port,
154 | username=foreman_user,
155 | password=foreman_pass,
156 | ssl=foreman_ssl)
157 |
158 | data = dict(login=login)
159 |
160 | try:
161 | # Search the user. If it does exist get detailed information
162 | found = theforeman.search_user(data=data)
163 | if found:
164 | user = theforeman.get_user(id=found.get('id'))
165 | else:
166 | user = None
167 | except ForemanError as e:
168 | module.fail_json(msg='Could not get user: {0}'.format(e.message))
169 |
170 | # Compare assigned values. password is not returned by Foreman and must be handled different
171 | for key in user_options:
172 | if key in module.params:
173 | data[key] = module.params[key]
174 |
175 | if roles:
176 | data['roles'] = get_roles(module, theforeman, roles)
177 | else:
178 | data['roles'] = []
179 |
180 | if not user and state == 'present':
181 | try:
182 | data['password'] = module.params['password']
183 | user = theforeman.create_user(data=data)
184 | return True, user
185 | except ForemanError as e:
186 | module.fail_json(msg='Could not create user: {0}'.format(e.message))
187 |
188 | if user:
189 | if state == 'absent':
190 | try:
191 | user, theforeman.delete_user(id=user.get('id'))
192 | return True, user
193 | except ForemanError as e:
194 | module.fail_json(msg='Could not delete user: {0}'.format(e.message))
195 |
196 | if (not all(user.get(key, data[key]) == data[key] for key in user_options)) or (
197 | not equal_roles(defined_roles=data.get('roles'), assigned_roles=user.get('roles'))):
198 | try:
199 | # module.fail_json(msg='{0}\n{1}'.format(user.get('roles'), data.get('roles')))
200 | user = theforeman.update_user(id=user.get('id'), data=data)
201 | return True, user
202 | except ForemanError as e:
203 | module.fail_json(msg='Could not update user: {0}'.format(e.message))
204 |
205 | return False, user
206 |
207 |
208 | def main():
209 | module = AnsibleModule(
210 | argument_spec=dict(
211 | admin=dict(type='str', required=False, default=False),
212 | auth_source_name=dict(type='str', default='Internal', aliases=['auth']),
213 | login=dict(type='str', required=True, aliases=['name']),
214 | firstname=dict(type='str', required=False),
215 | lastname=dict(type='str', required=False),
216 | mail=dict(type='str', required=False),
217 | state=dict(type='str', default='present', choices=['present', 'absent']),
218 | password=dict(type='str', required=False, no_log=True),
219 | roles=dict(type='list', required=False),
220 | foreman_host=dict(type='str', default='127.0.0.1'),
221 | foreman_port=dict(type='str', default='443'),
222 | foreman_user=dict(type='str', required=True),
223 | foreman_pass=dict(type='str', required=True, no_log=True),
224 | foreman_ssl=dict(type='bool', default=True)
225 | ),
226 | )
227 |
228 | if not foremanclient_found:
229 | module.fail_json(msg='python-foreman module is required. See https://github.com/Nosmoht/python-foreman.')
230 |
231 | changed, user = ensure(module)
232 | module.exit_json(changed=changed, user=user)
233 |
234 |
235 | from ansible.module_utils.basic import *
236 |
237 | if __name__ == '__main__':
238 | main()
239 |
--------------------------------------------------------------------------------
/foreman_usergroup.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding: utf-8 -*-
3 | #
4 | # Ansible module to manage Foreman usergroup resources.
5 | #
6 | # This module is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # This software is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with this software. If not, see .
18 | #
19 | # (C) 2017 Guido Günther
20 |
21 | DOCUMENTATION = '''
22 | ---
23 | module: foreman_usergroup
24 | short_description: Manage Foreman Usergroup using Foreman API v2
25 | description:
26 | - Create and delete Foreman Usergroups using Foreman API v2
27 | options:
28 | name:
29 | description: name of the usergroup
30 | required: true
31 | users:
32 | description: user of this usergroup. Users are identified by their
33 | login.
34 | required: false
35 | usergroups:
36 | description: usergroups of this usergroup. Usergroups can be
37 | nested.
38 | required: false
39 | roles:
40 | description: roles assigned to this usergroup
41 | required: false
42 | state:
43 | description: State of usergroup
44 | required: false
45 | default: present
46 | choices: ["present", "absent"]
47 | foreman_host:
48 | description: Hostname or IP address of Foreman system
49 | required: false
50 | default: 127.0.0.1
51 | foreman_port:
52 | description: Port of Foreman API
53 | required: false
54 | default: 443
55 | foreman_user:
56 | description: Username to be used to authenticate on Foreman
57 | required: true
58 | foreman_pass:
59 | description: Password to be used to authenticate user on Foreman
60 | required: true
61 | foreman_ssl:
62 | description: Enable SSL when connecting to Foreman API
63 | required: false
64 | default: true
65 | notes:
66 | - Requires the python-foreman package to be installed. See https://github.com/Nosmoht/python-foreman.
67 | - This module does currently not update already existing groups
68 | version_added: "2.0"
69 | author: "Thomas Krahn (@nosmoht)"
70 | '''
71 |
72 | EXAMPLES = '''
73 | - name: Ensure a simple usergroup
74 | foreman_usergroup:
75 | name: poweradmins
76 | roles:
77 | - "Edit hostgroups"
78 | - Manager
79 | users:
80 | - user1
81 | - user2
82 | state: present
83 | foreman_host: 127.0.0.1
84 | foreman_port: 443
85 | foreman_user: admin
86 | foreman_pass: secret
87 | '''
88 |
89 | try:
90 | from foreman.foreman import *
91 |
92 | foremanclient_found = True
93 | except ImportError:
94 | foremanclient_found = False
95 |
96 |
97 | def get_ids(module, theforeman, res_type, names, field='name'):
98 | result = []
99 | try:
100 | searcher = getattr(theforeman, "search_{0}".format(res_type))
101 | except AttributeError:
102 | module.fail_json(msg="Don't know how to search for {0}".format(res_type))
103 |
104 | for name in names:
105 | try:
106 | res = searcher(data={field: name})
107 | if not res:
108 | module.fail_json(msg="Could not find '{0}' of type {1}".format(name, res_type))
109 | result.append(res.get('id'))
110 | except ForemanError as e:
111 | module.fail_json(msg="Could not get '{0}' of type {1}: {2}".format(name,
112 | res_type,
113 | e.message))
114 | return result
115 |
116 |
117 | def ensure(module):
118 | name = module.params['name']
119 | state = module.params['state']
120 | roles = module.params['roles']
121 | users = module.params['users']
122 | usergroups = module.params['usergroups']
123 |
124 | foreman_host = module.params['foreman_host']
125 | foreman_port = module.params['foreman_port']
126 | foreman_user = module.params['foreman_user']
127 | foreman_pass = module.params['foreman_pass']
128 | foreman_ssl = module.params['foreman_ssl']
129 |
130 | theforeman = Foreman(hostname=foreman_host,
131 | port=foreman_port,
132 | username=foreman_user,
133 | password=foreman_pass,
134 | ssl=foreman_ssl)
135 |
136 | data = dict(name=name)
137 |
138 | try:
139 | usergroup = theforeman.search_usergroup(data)
140 | except ForemanError as e:
141 | module.fail_json(msg='Could not get usergroup: {0}'.format(e.message))
142 |
143 | if not usergroup and state == 'present':
144 | if usergroups:
145 | data['usergroup_ids'] = get_ids(module, theforeman, 'usergroup', usergroups)
146 | if roles:
147 | data['role_ids'] = get_ids(module, theforeman, 'role', roles)
148 | if users:
149 | data['user_ids'] = get_ids(module, theforeman, 'user', users, field='login')
150 |
151 | try:
152 | usergroup = theforeman.create_usergroup(data=data)
153 | return True, usergroup
154 | except ForemanError as e:
155 | module.fail_json(msg='Could not create usergroup: {0}'.format(e.message))
156 |
157 | if usergroup and state == 'absent':
158 | try:
159 | usergroup = theforeman.delete_usergroup(id=usergroup['id'])
160 | except ForemanError as e:
161 | module.fail_json(msg='Could not delete usergroup: {0}'.format(e.message))
162 | return True, usergroup
163 |
164 | return False, usergroup
165 |
166 |
167 | def main():
168 | module = AnsibleModule(
169 | argument_spec=dict(
170 | state=dict(type='str', default='present', choices=['present', 'absent']),
171 | name=dict(type='str', required=True),
172 | roles=dict(type='list', required=False),
173 | users=dict(type='list', required=False),
174 | usergroups=dict(type='list', required=False),
175 | foreman_host=dict(type='str', default='127.0.0.1'),
176 | foreman_port=dict(type='str', default='443'),
177 | foreman_user=dict(type='str', required=True),
178 | foreman_pass=dict(type='str', required=True, no_log=True),
179 | foreman_ssl=dict(type='bool', default=True)
180 | ),
181 | )
182 |
183 | if not foremanclient_found:
184 | module.fail_json(msg='python-foreman module is required. See https://github.com/Nosmoht/python-foreman.')
185 |
186 | changed, usergroup = ensure(module)
187 | module.exit_json(changed=changed, usergroup=usergroup)
188 |
189 |
190 | from ansible.module_utils.basic import *
191 |
192 | if __name__ == '__main__':
193 | main()
194 |
--------------------------------------------------------------------------------
/module_utils/foreman_utils.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # (c) Radim Janča (Cesnet) 2018
3 |
4 | try:
5 | from foreman.foreman import *
6 | except ImportError:
7 | module.fail_json(msg='python-foreman module is required. See https://github.com/Nosmoht/python-foreman.')
8 |
9 |
10 | def init_foreman_client(module):
11 | return Foreman(hostname=module.params['foreman_host'],
12 | port=module.params['foreman_port'],
13 | username=module.params['foreman_user'],
14 | password=module.params['foreman_pass'],
15 | ssl=module.params['foreman_ssl'])
16 |
17 |
18 | def equal_dict_lists(l1, l2, compare_key='name'):
19 | s1 = set(map(lambda x: x[compare_key], l1))
20 | s2 = set(map(lambda x: x[compare_key], l2))
21 | return s1 == s2
22 |
23 |
24 | def dict_list_to_list(alist, key):
25 | result = list()
26 | if alist:
27 | for item in alist:
28 | result.append(item.get(key, None))
29 | return result
30 |
31 |
32 | def get_resource_ids(resource_type, module, theforeman, resource_names, search_field='name'):
33 | result = []
34 | for i in range(0, len(resource_names)):
35 | try:
36 | resource = theforeman.search_resource(resource_type=resource_type, data={search_field: resource_names[i]})
37 | if not resource:
38 | module.fail_json(msg='Could not find {type} {name}'.format(
39 | type=resource_type,name=resource_names[i]))
40 | result.append(resource.get('id'))
41 | except ForemanError as e:
42 | module.fail_json(msg='Search for {type} \'{name}\' throws an Error: {err}'.format(
43 | type=resource_type,name=resource_names[i],err=e.message))
44 | return result
45 |
46 | def get_organization_ids(module, theforeman, organizations):
47 | return get_resource_ids(ORGANIZATIONS, module, theforeman, organizations)
48 | def get_location_ids(module, theforeman, locations):
49 | return get_resource_ids(LOCATIONS, module, theforeman, locations)
50 | def get_operatingsystem_ids(module, theforeman, operating_systems):
51 | return get_resource_ids(OPERATINGSYSTEMS, module, theforeman, operating_systems, search_field='title')
52 |
53 |
54 | def organizations_equal(data, resource):
55 | if 'organization_ids' in data:
56 | if not ('organizations' in resource):
57 | return False
58 | else:
59 | organization_ids = dict_list_to_list(resource['organizations'], 'id')
60 | if set(data['organization_ids']) != set(organization_ids):
61 | return False
62 | return True
63 |
64 |
65 | def locations_equal(data, resource):
66 | if 'location_ids' in data:
67 | if not ('locations' in resource):
68 | return False
69 | else:
70 | location_ids = dict_list_to_list(resource['locations'], 'id')
71 | if set(data['location_ids']) != set(location_ids):
72 | return False
73 | return True
74 |
75 |
76 | def operatingsystems_equal(data, resource):
77 | if 'operatingsystem_ids' in data:
78 | if not ('operatingsystems' in resource):
79 | return False
80 | else:
81 | operatingsystem_ids = dict_list_to_list(resource['operatingsystems'], 'id')
82 | if set(data['operatingsystem_ids']) != set(operatingsystem_ids):
83 | return False
84 | return True
85 |
--------------------------------------------------------------------------------