#!/usr/bin/perl use JSON::XS; use Getopt::Long; use Pod::Usage; =head1 NAME inventory - Ansible Dynamic Inventory script =head1 SYNOPSIS inventory --list | --host --list: return YAML compatible JSON inventory of all hosts --host : return YAML compatible JSON with all variables defined for the given host =head1 DESCRIPTION This is a completely useless example of a dynamic inventory, since it just returns the included ini-style inventory, in JSON (or YAML). To test it do: $ ansible -i --list-hosts =cut my %inventory = ( _meta => { hostvars => {} }, all => { children => ['ungrouped'] }, ungrouped => {} ); sub hosts { my $host = shift; #expand ranges in hostnames # ie for each [a:b] in the name use perls range operator a..b return $host !~ m{^(.*?)\[(.*?):(.*?)\](.*)} ? $host : map { hosts($_) } map { $1.$_.$4 } $2..$3; } sub group { my ($group, $host, @args) = (shift,split(/\s+/,shift)); !exists $inventory{$group} && ($inventory{$group} = {'hosts'=> []}); exists $inventory{$group}->{hosts} || ($inventory{$group}->{hosts} = []); # need to handle expansion of ranges in host names for my $host (hosts($host)) { push(@{$inventory{$group}->{hosts}},$host); for (@args) { exists $inventory{_meta}->{hostvars}->{$host} || ($inventory{_meta}->{hostvars}->{$host} = {} ); my ($k, $v) = split('=',$_); $inventory{_meta}->{hostvars}->{$host}->{$k} = $v; } } } sub vars { my ($group, $k, $v) = (shift,split('=',shift)); !exists $inventory{$group} && ($inventory{$group} = {'vars'=> {}}); exists $inventory{$group}->{vars} || ($inventory{$group}->{vars} = {}); $inventory{$group}->{vars}->{$k} = $v; } sub children { my ($group, $line) = @_; !exists $inventory{$group} && ($inventory{$group} = {'children'=> []}); exists $inventory{$group}->{children} || ($inventory{$group}->{children} = []); push(@{$inventory{$group}->{children}},$line); } sub inventory2json { my $group = "ungrouped"; my $state = \&group; while ( ) { chomp; m{^(\s*|#.*)$} && next; m{\[([^:]+)(:vars|:children)?\]} && do { $group = $1; $state = defined($2) ? substr($2,1) : "group"; $state eq "group" && push(@{$inventory{all}->{children}},$group); $state = \&$state; next; }; $state->($group,$_); } } my ($list, $host ) = (undef, undef); GetOptions("list" => \$list, "host=s" => \$host) or pod2usage(2); defined $list == defined $host && pod2usage('Need exactly one option either --list or --host'); inventory2json; $list && print JSON::XS->new->pretty->utf8->space_after(1)->encode(\%inventory); __DATA__ # Each group represents a role or a location # ie. localhost ansible_connection=local ansible_become=False [default] pallas.ai.rug.nl ansible_become=true ansible_ssh_user=remco ai17873.ai.rug.nl ansible_become=true ansible_ssh_user=rwouts 129.125.5.[1:255] ansible_become=true 129.125.74.[1:255] ansible_become=true ansible_ssh_user=rwouts ai178125.ai.rug.nl ansible_ssh_user=rwouts ansible_become=true ai178126.ai.rug.nl ansible_ssh_user=rwouts ansible_become=True monk01.hpc.rug.nl ansible_ssh_user=rwouts ansible_become=True lwp132.lwp.rug.nl ansible_ssh_user=rwouts ansible_become=True #locations # [esx] turing13.housing.rug.nl role=TimeCapsule turing14.housing.rug.nl role=TestMachine turing15.housing.rug.nl role=AIFileServer lwp[01:28].service.rug.nl spruitje.service.rug.nl lwp[01:28].service.rug.nl spruitje.service.rug.nl lwp29.lwp.rug.nl role=TracServer lwp30.lwp.rug.nl role=AfsFileServer trac.lwp.rug.nl role=TracServer afs.lwp.rug.nl role=AfsFileServer [groningen:children] esx default lwp [groningen:vars] timezone=Europe/Amsterdam #Nijenbrg [5116.315] 129.125.28.[145:166] #Harmonie [1313.266] 129.125.176.[215:225] [1313.267] 129.125.176.[118:129] #MM1 [1313.258] 129.125.145.[26:50] #MM2 [1313.257] 129.125.145.[51:75] #MM3 [1313.265] 129.125.145.[1:25] [5173.169] 129.125.157.[1:45] [5116.303] 129.125.28.[55:79] [5116.310] 129.125.28.[20:51] [5116.315] 129.125.28.[145:166] [5161.204] 129.125.74.[107:118] [5161.206] 129.125.74.[156:159] [5161.216] 129.125.74.[30:47] [5161.228] 129.125.74.[73:103] [5161.273] 129.125.74.[122:154] [5161.280] ai178130.ai.rug.nl ai178133.ai.rug.nl ai178139.ai.rug.nl ai178140.ai.rug.nl ai178141.ai.rug.nl ai178142.ai.rug.nl ai178143.ai.rug.nl ai178144.ai.rug.nl ai178145.ai.rug.nl ai178146.ai.rug.nl [5161.283] 129.125.74.[161:185] [bernoulliborg:children] 5161.204 5161.206 5161.216 5161.228 5161.273 5161.283 [nijenborg:children] 5116.303 5116.310 5116.315 # #roles # [timecapsule] # turing13.housing.rug.nl [timecapsule:vars] [pi] pi ansible_ssh_user=pi ansible_become=True ansible_host=129.125.178.200 [lwp3] 2.ai ansible_ssh_user=rwouts ansible_become=True haytabo.let.rug.nl ansible_ssh_user=rwouts ansible_become=True theuser=rwouts [lwp] turing10.housing.rug.nl turing13.housing.rug.nl role=TimeCapsule turing14.housing.rug.nl role=TestMachine turing15.housing.rug.nl role=AIFileServer lwp29.lwp.rug.nl role=TracServer lwp30.lwp.rug.nl role=AfsFileServer trac.lwp.rug.nl role=TracServer afs.lwp.rug.nl role=AfsFileServer debian lwp32.lwp.rug.nl ansible_become=True lwp31.lwp.rug.nl ansible_become=True themis.housing.rug.nl ansible_become=True 129.125.178.[1:255] ansible_become=True cit-zb-3-147.rc.rug.nl ansible_ssh_user=rwouts ansible_become=True theuser=rwouts [lwp:children] bernoulliborg nijenborg [lwp:vars] ansible_ssh_user=rwouts ansible_become=True become_user=rwouts [ulab] ai178174.ai.rug.nl ansible_ssh_user=rwouts ansible_become=True become_user=rwouts ai178175.ai.rug.nl ansible_ssh_user=rwouts ansible_become=True become_user=rwouts ai17850.ai.rug.nl ansible_ssh_user=admin ansible_become=True become_user=admin [ulab:children] 5161.280 [ulab:vars] ansible_user=usabilitylab ansible_timeout=40 ansible_become=True become_user=usabilitylab [alice:children] 5161.204 5161.206 5161.216 5161.228 5161.273 5161.283 #These are the AI servers (iron) [ai] tcw1 ansible_host=129.125.14.181 aps ansible_host=129.125.14.183 bak ansible_host=129.125.14.184 tcw2 ansible_host=129.125.14.185 [ai:vars] ansible_user=root ansible_become=False ansible_ssh_private_key_file=~/.ssh/old-dss-keys/id_dsa [ai_vm] turing15.housing.rug.nl turing18.housing.rug.nl mail.ai.rug.nl imap.ai.rug.nl www.ai.rug.nl