├── README.asciidoc ├── ldap ├── README.asciidoc ├── ansible.ldif ├── ansible.schema ├── ldap_inv.py └── structure.ldif └── rhn └── rhn_inv.py /README.asciidoc: -------------------------------------------------------------------------------- 1 | Ansible inventory scripts 2 | ------------------------- 3 | 4 | These scripts are NOT production ready. Use at your own risk 5 | -------------------------------------------------------------------------------- /ldap/README.asciidoc: -------------------------------------------------------------------------------- 1 | Ansible LDAP inventory 2 | ---------------------- 3 | This script can be used to use LDAP as a source for your Ansible inventory. 4 | It is currently under development and available here for people who want to 5 | do something similar. Expect more updates later on. 6 | 7 | Included is an LDIF export so you can get an idea of the LDAP structure. 8 | 9 | - All hosts are contained in a OU (ex hosts) 10 | - groups need to be groupOfNames 11 | - you can have a group inside a group. These wil be listed as children 12 | - The directory is extended with a custom schema created by @jpmens. The file 13 | is included as ansible.schema and ansible.ldif for use with OLC. 14 | 15 | example output 16 | -------------- 17 | 18 | --list : 19 | [bash] 20 | ---- 21 | → ~/projects/ansible-ldap/inventory.py --list 22 | { 23 | "infrasrv": { 24 | "children": [], 25 | "hosts": [ 26 | "infra-03.prod.btr.local" 27 | ], 28 | "vars": {} 29 | }, 30 | "proxyservers": { 31 | "children": [ 32 | "webservers" 33 | ], 34 | "hosts": [ 35 | "host01", 36 | "host02" 37 | ], 38 | "vars": { 39 | "ansible_ssh_port": "222", 40 | "jboss": "8080", 41 | "ssh_port": "222" 42 | } 43 | }, 44 | "webservers": { 45 | "children": [], 46 | "hosts": [ 47 | "host02", 48 | "web01", 49 | "web03" 50 | ], 51 | "vars": {} 52 | } 53 | } 54 | ---- 55 | 56 | --host 57 | [bash] 58 | ---- 59 | inventory.py --host infra-03.prod.btr.local 60 | { 61 | "ansible_ssh_port": "22" 62 | } 63 | 64 | ---- 65 | -------------------------------------------------------------------------------- /ldap/ansible.ldif: -------------------------------------------------------------------------------- 1 | ## ansible.schema Copyright (c) 2013 by Jan-Piet Mens 2 | ## 3 | ## Redistribution and use in source and binary forms, with or without 4 | ## modification, are permitted provided that the following conditions 5 | ## are met: 6 | ## 7 | ## 1. Redistributions of source code must retain the above copyright 8 | ## notice, this list of conditions and the following disclaimer. 9 | ## 10 | ## 2. Redistributions in binary form must reproduce the above copyright 11 | ## notice, this list of conditions and the following disclaimer in the 12 | ## documentation and/or other materials provided with the distribution. 13 | ## 14 | ## 3. All advertising materials mentioning features or use of this software 15 | ## must display the following acknowledgement: 16 | ## This product includes software developed by Jan-Piet Mens and his 17 | ## contributors. 18 | ## 19 | ## 4. Neither the name of the Author nor the names of its contributors 20 | ## may be used to endorse or promote products derived from this software 21 | ## without specific prior written permission. 22 | ## 23 | ## THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 24 | ## ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 | ## IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 | ## ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 27 | ## FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 | ## DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 | ## OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 | ## HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 | ## LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 | ## OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 | ## SUCH DAMAGE. 34 | ## 35 | 36 | # OpenLDAP schema file for Ansible. Requires core schema. In particular, 37 | # we propose to use `device' as a structural objectclass, which brings 38 | # the following attribute types: 39 | # 40 | # MUST ( cn ) 41 | # MAY ( serialNumber $ seeAlso $ owner $ ou $ o $ l $ description ) 42 | # 43 | # 44 | # The OID numbers used herein are officially registered, and I have reserved 45 | # these ranges for use by Ansible: 46 | # 47 | # 1.3.6.1.4.1.7637.70 Ansible 48 | # 1.3.6.1.4.1.7637.70.1.1 LDAP ObjectClasses 49 | # 50 | # 1.3.6.1.4.1.7637.70.1.2 LDAP AttributeTypes 51 | # 52 | # ansibleVar: ansible_ssh_host=localhost 53 | dn: cn=ansible,cn=schema,cn=config 54 | objectClass: olcSchemaConfig 55 | cn: core 56 | olcattributetypes: ( 1.3.6.1.4.1.7637.70.1.2.1 NAME 'ansibleVar' DESC 'A variable=value setting for an Ansible host' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024} ) 57 | olcattributetypes: ( 1.3.6.1.4.1.7637.70.1.2.2 NAME 'ansibleGroupVar' DESC 'A variable=value setting for an Ansible Group' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024} ) 58 | olcobjectclasses: ( 1.3.6.1.4.1.7637.70.1.1.1 NAME 'ansibleHost' DESC 'Ansible host entry' SUP top AUXILIARY MAY ( ansibleVar ) ) 59 | olcobjectclasses: ( 1.3.6.1.4.1.7637.70.1.1.2 NAME 'ansibleGroup' DESC 'Ansible group entry' SUP top AUXILIARY MAY ( ansibleGroupVar ) ) 60 | -------------------------------------------------------------------------------- /ldap/ansible.schema: -------------------------------------------------------------------------------- 1 | ## ansible.schema Copyright (c) 2013 by Jan-Piet Mens 2 | ## 3 | ## Redistribution and use in source and binary forms, with or without 4 | ## modification, are permitted provided that the following conditions 5 | ## are met: 6 | ## 7 | ## 1. Redistributions of source code must retain the above copyright 8 | ## notice, this list of conditions and the following disclaimer. 9 | ## 10 | ## 2. Redistributions in binary form must reproduce the above copyright 11 | ## notice, this list of conditions and the following disclaimer in the 12 | ## documentation and/or other materials provided with the distribution. 13 | ## 14 | ## 3. All advertising materials mentioning features or use of this software 15 | ## must display the following acknowledgement: 16 | ## This product includes software developed by Jan-Piet Mens and his 17 | ## contributors. 18 | ## 19 | ## 4. Neither the name of the Author nor the names of its contributors 20 | ## may be used to endorse or promote products derived from this software 21 | ## without specific prior written permission. 22 | ## 23 | ## THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 24 | ## ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 | ## IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 | ## ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 27 | ## FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 | ## DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 | ## OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 | ## HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 | ## LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 | ## OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 | ## SUCH DAMAGE. 34 | ## 35 | 36 | # OpenLDAP schema file for Ansible. Requires core schema. In particular, 37 | # we propose to use `device' as a structural objectclass, which brings 38 | # the following attribute types: 39 | # 40 | # MUST ( cn ) 41 | # MAY ( serialNumber $ seeAlso $ owner $ ou $ o $ l $ description ) 42 | # 43 | # 44 | # The OID numbers used herein are officially registered, and I have reserved 45 | # these ranges for use by Ansible: 46 | # 47 | # 1.3.6.1.4.1.7637.70 Ansible 48 | # 1.3.6.1.4.1.7637.70.1.1 LDAP ObjectClasses 49 | # 50 | # 1.3.6.1.4.1.7637.70.1.2 LDAP AttributeTypes 51 | # 52 | 53 | 54 | # ansibleVar: ansible_ssh_host=localhost 55 | 56 | attributetype ( 1.3.6.1.4.1.7637.70.1.2.1 NAME 'ansibleVar' 57 | DESC 'A variable=value setting for an Ansible host' 58 | EQUALITY caseIgnoreMatch 59 | SUBSTR caseIgnoreSubstringsMatch 60 | SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024} 61 | ) 62 | 63 | attributetype ( 1.3.6.1.4.1.7637.70.1.2.2 NAME 'ansibleGroupVar' 64 | DESC 'A variable=value setting for an Ansible Group' 65 | EQUALITY caseIgnoreMatch 66 | SUBSTR caseIgnoreSubstringsMatch 67 | SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024} 68 | ) 69 | 70 | objectclass ( 1.3.6.1.4.1.7637.70.1.1.1 NAME 'ansibleHost' 71 | DESC 'Ansible host entry' 72 | SUP top AUXILIARY 73 | MAY ( ansibleVar ) 74 | ) 75 | 76 | objectclass ( 1.3.6.1.4.1.7637.70.1.1.2 NAME 'ansibleGroup' 77 | DESC 'Ansible group entry' 78 | SUP top AUXILIARY 79 | MAY ( ansibleGroupVar ) 80 | ) 81 | -------------------------------------------------------------------------------- /ldap/ldap_inv.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | ## ansible ldap inventory script Copyright (c) 2013 by Vincent Van der 3 | ## Kussen 4 | ## 5 | ## This program is free software: you can redistribute it and/or modify 6 | ## it under the terms of the GNU General Public License as published by 7 | ## the Free Software Foundation, either version 3 of the License, or 8 | ## (at your option) any later version. 9 | ## 10 | ## This program is distributed in the hope that it will be useful, 11 | ## but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ## GNU General Public License for more details. 14 | ## 15 | ## You should have received a copy of the GNU General Public License 16 | ## along with this program. If not, see . 17 | 18 | import ldap 19 | import re 20 | import sys 21 | import operator 22 | import os 23 | import shlex 24 | 25 | try: 26 | import simplejson as json 27 | except ImportError: 28 | import json 29 | 30 | # establish connection with LDAP server 31 | try: 32 | l = ldap.initialize(os.getenv("LDAPHOST", "")) 33 | username = os.getenv("LDAPBINDDN", "") 34 | password = os.getenv("LDAPBINDPW", "") 35 | l.set_option(ldap.OPT_PROTOCOL_VERSION,ldap.VERSION3) 36 | l.bind_s(username, password, ldap.AUTH_SIMPLE) 37 | 38 | except ldap.LDAPError, e: 39 | print e 40 | 41 | # LDAP variables 42 | baseDN = os.getenv("LDAPBASEDN", 'ou=ansible, dc=ansible, dc=local') 43 | searchScope = ldap.SCOPE_SUBTREE 44 | attrs = None 45 | 46 | # We only want the groups and not groups + computer CNs 47 | groupsearchFilter = '(&(objectClass=groupOfNames)(cn=*))' 48 | 49 | # ------------------------------------------------------------------ 50 | # function to split the ansibleVar (key=value) in a hashed key value. 51 | 52 | #def generatekv(ansibleAttribute): 53 | # var = {} 54 | # attr = re.match(r'(.*)=(.*)', ansibleAttribute) 55 | # key = attr.group(1) 56 | # value = attr.group(2) 57 | # var[key] = value 58 | # return var 59 | 60 | def generatekv(ansibleAttribute): 61 | attr = re.match(r'(.*)=(.*)', ansibleAttribute) 62 | key = attr.group(1) 63 | value = attr.group(2) 64 | bla = (key,value) 65 | var = (key,value) 66 | return var 67 | 68 | # ------------------------------------------------------------------- 69 | # define if a groupmember is a host or a child group 70 | # 71 | def detect_group(): 72 | groupsearchfilter = '(objectClass=ansibleGroup)' 73 | result = l.search_s(baseDN, searchScope, groupsearchfilter) 74 | groups = [] 75 | for item in result: 76 | res = item[1] 77 | groupname = res['cn'][0] 78 | groups.append(groupname) 79 | return groups 80 | 81 | # ------------------------------------------------------------------- 82 | # get a list of groups with their hosts 83 | 84 | def getlist(): 85 | try: 86 | inv = {} 87 | result = l.search_s(baseDN, searchScope, groupsearchFilter) 88 | # putting group list here otherwise it gets called for each available 89 | # group in ldap -> keeps growing 90 | groups = detect_group() 91 | for item in result: 92 | res = item[1] 93 | group = res['cn'][0] 94 | hostgroup = [ ] 95 | varlist = [ ] 96 | children = [ ] 97 | res = dict(item[1]) 98 | #print res 99 | for key, value in res.iteritems(): 100 | if key == "member": 101 | for item in value: 102 | host = re.match(r'cn=([^,]*)', item) 103 | host = host.group(1) 104 | if host in groups: 105 | children.append(host) 106 | else: 107 | hostgroup.append(host) 108 | if key == "ansibleGroupVar": 109 | for item in value: 110 | ansiblevar = generatekv(item) 111 | varlist.append(ansiblevar) 112 | inv[group] = {"hosts": hostgroup} 113 | inv[group]['vars'] = dict(varlist) 114 | inv[group]["children"]= children 115 | print json.dumps(inv, sort_keys=True, indent=2) 116 | 117 | except ldap.LDAPError, e: 118 | print e 119 | 120 | l.unbind_s() 121 | 122 | # -------------------------------------------------------------------- 123 | # get all attributes from a host 124 | 125 | def getdetails(host): 126 | hostsearchFilter = "cn=%s" % host 127 | details = {} 128 | varlist = [] 129 | result = l.search_s(baseDN, searchScope, hostsearchFilter) 130 | for item in result: 131 | res = dict(item[1]) 132 | for key, values in res.iteritems(): 133 | if key == "ansibleVar": 134 | for val in values: 135 | # Ensure we safely convert values of the form 136 | # ansibleVar: key=val=x=y=z 137 | for arg in shlex.split(val): 138 | k, v = arg.split('=', 1) 139 | # don't create list when only one item is found 140 | items = v.split() 141 | if len(items) == 1: 142 | varlist.append((k, v)) 143 | # return list as value when more items are found 144 | else: 145 | valuelist = v.split(',') 146 | varlist.append((k, valuelist)) 147 | details = dict(varlist) 148 | 149 | print json.dumps(details, sort_keys=True, indent=2) 150 | l.unbind_s() 151 | 152 | # ---------------------------------------------------------------------- 153 | # get list of machines from RHN 154 | if len(sys.argv) == 2 and (sys.argv[1] == '--list'): 155 | getlist() 156 | 157 | #get details from a host 158 | elif len(sys.argv) == 3 and (sys.argv[1] == '--host'): 159 | host = sys.argv[2] 160 | getdetails(host) 161 | 162 | else: 163 | print "usage --list or --host " 164 | sys.exit(1) 165 | -------------------------------------------------------------------------------- /ldap/structure.ldif: -------------------------------------------------------------------------------- 1 | version: 1 2 | 3 | dn: dc=ansible,dc=local 4 | objectClass: organization 5 | objectClass: dcObject 6 | dc: ansible 7 | o: Ansible testserver 8 | description: Ansible testserver 9 | 10 | dn: ou=ansible,dc=ansible,dc=local 11 | objectClass: top 12 | objectClass: organizationalUnit 13 | ou: computers 14 | 15 | dn: cn=host01,ou=hosts,ou=ansible,dc=ansible,dc=local 16 | objectClass: ansibleHost 17 | objectClass: top 18 | objectClass: device 19 | cn: host01 20 | ansibleVar: in_port=333 21 | 22 | dn: cn=host02,ou=hosts,ou=ansible,dc=ansible,dc=local 23 | objectClass: device 24 | objectClass: top 25 | objectClass: ansibleHost 26 | cn: host02 27 | ansibleVar: ssh_port=222 28 | 29 | dn: cn=proxyservers,ou=groups,ou=ansible,dc=ansible,dc=local 30 | objectClass: ansibleGroup 31 | objectClass: top 32 | objectClass: groupOfNames 33 | cn: proxyservers 34 | member: cn=host01,ou=ansible,dc=ansible,dc=local 35 | member: cn=host02,ou=ansible,dc=ansible,dc=local 36 | member: cn=webservers,ou=groups,ou=ansible,dc=ansible,dc=local 37 | ansibleGroupVar: ansible_ssh_port=222 38 | ansibleGroupVar: ssh_port=222 39 | ansibleGroupVar: jboss=8080 40 | 41 | dn: cn=webservers,ou=groups,ou=ansible,dc=ansible,dc=local 42 | objectClass: groupOfNames 43 | objectClass: top 44 | objectClass: ansibleGroup 45 | cn: webservers 46 | member: cn=host02,ou=ansible,dc=ansible,dc=local 47 | member: cn=web01,ou=ansible,dc=ansible,dc=local 48 | member: cn=web03,ou=ansible,dc=ansible,dc=local 49 | 50 | dn: cn=web01,ou=hosts,ou=ansible,dc=ansible,dc=local 51 | objectClass: device 52 | objectClass: top 53 | objectClass: ansibleHost 54 | cn: web01 55 | 56 | dn: cn=web03,ou=hosts,ou=ansible,dc=ansible,dc=local 57 | objectClass: device 58 | objectClass: top 59 | objectClass: ansibleHost 60 | cn: web03 61 | 62 | dn: ou=hosts,ou=ansible,dc=ansible,dc=local 63 | objectClass: top 64 | objectClass: organizationalUnit 65 | ou: hosts 66 | 67 | dn: ou=groups,ou=ansible,dc=ansible,dc=local 68 | objectClass: top 69 | objectClass: organizationalUnit 70 | ou: groups 71 | 72 | dn: cn=infra-03.prod.btr.local,ou=hosts,ou=ansible,dc=ansible,dc=local 73 | objectClass: device 74 | objectClass: top 75 | objectClass: ansibleHost 76 | cn: infra-03.prod.btr.local 77 | ansibleVar: ansible_ssh_port=22 78 | 79 | dn: cn=infrasrv,ou=groups,ou=ansible,dc=ansible,dc=local 80 | objectClass: groupOfNames 81 | objectClass: top 82 | objectClass: ansibleGroup 83 | cn: infrasrv 84 | member: cn=infra-03.prod.btr.local,ou=hosts,ou=ansible,dc=ansible,dc=local 85 | 86 | -------------------------------------------------------------------------------- /rhn/rhn_inv.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | ## 3 | ## ansible RHN inventory script Copyright (c) 2013 by Vincent Van der 4 | ## Kussen 5 | ## 6 | ## This program 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 program 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 program. If not, see . 18 | ##¬ 19 | 20 | 21 | import xmlrpclib 22 | import operator 23 | import sys 24 | 25 | try: 26 | import json 27 | except ImportError: 28 | import simplejson as json 29 | 30 | pwd = "" 31 | saturl = "" 32 | user = "" 33 | 34 | # RHN connection 35 | client = xmlrpclib.Server(saturl, verbose=0) 36 | session = client.auth.login(user, pwd) 37 | 38 | # get all groups from RHN 39 | groups = client.systemgroup.listAllGroups(session) 40 | 41 | # --------------------------------------------------------------------------- 42 | # Get the name of each group and find all hosts in it and 43 | # add it to the hashmap 44 | 45 | #grp = { } 46 | 47 | def getlist(): 48 | grp = { } 49 | for item in groups: 50 | group = item.get('name') 51 | grp[group] = [] 52 | machines = client.systemgroup.listSystems(session, item['name']) 53 | for m in machines: 54 | sysid = int(m['id']) 55 | ip = client.system.getNetwork(session, sysid) 56 | grp[group].append(ip['hostname']) 57 | #grp[group].append(m['name']) 58 | print json.dumps(grp) 59 | sys.exit(0) 60 | 61 | # -------------------------------------------------------------------------- 62 | 63 | def getdetails(host): 64 | details = { } 65 | hosts = client.system.listUserSystems(session) 66 | for h in hosts: 67 | if h.get('name') == host: 68 | sysid = int(h['id']) 69 | ip = client.system.getNetwork(session, sysid) 70 | #details[host].append(ip['ip']) 71 | details['ipaddr'] = ip['ip'] 72 | details['rhid'] = str(sysid) 73 | details['rhsysname'] = host 74 | #print json.dumps(details, sort_keys=True, indent=2) 75 | print json.dumps(details) 76 | sys.exit(0) 77 | 78 | # get list of machines from RHN 79 | if len(sys.argv) == 2 and (sys.argv[1] == '--list'): 80 | getlist() 81 | 82 | #get details from a host 83 | elif len(sys.argv) == 3 and (sys.argv[1] == '--host'): 84 | host = sys.argv[2] 85 | getdetails(host) 86 | 87 | else: 88 | print "usage --list or --host " 89 | sys.exit(1) 90 | --------------------------------------------------------------------------------