1# Copyright 2021 Northern.tech AS 2 3# This file is part of CFEngine 3 - written and maintained by Northern.tech AS. 4 5# This program is free software; you can redistribute it and/or modify it 6# under the terms of the GNU General Public License as published by the 7# Free Software Foundation; version 3. 8 9# This program is distributed in the hope that it will be useful, 10# but WITHOUT ANY WARRANTY; without even the implied warranty of 11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12# GNU General Public License for more details. 13 14# You should have received a copy of the GNU General Public License 15# along with this program; if not, write to the Free Software 16# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 17 18# To the extent this program is licensed as part of the Enterprise 19# versions of Cfengine, the applicable Commercial Open Source License 20# (COSL) may apply to this file if you as a licensee so wish it. See 21# included file COSL.txt. 22 23#+begin_src cfengine3 24body common control 25{ 26 bundlesequence => { run }; 27} 28 29bundle agent run 30{ 31 vars: 32 # you can also readjson() from a file 33 "groups" data => parsejson('{ 34"ByGroup": 35{ 36 "App1": 37 [ 38 "GrpA", 39 "GrpB", 40 "GrpC" 41 ], 42 "App2": 43 [ 44 "GrpX", 45 "GrpY", 46 "GrpZ" 47 ] 48}, 49 50"ByApp": 51{ 52 "App1": 53 [ 54 "Host1", 55 "Host2", 56 "Host3" 57 ], 58 "App2": 59 [ 60 "Host1", 61 "Host3" 62 ] 63} 64}'); 65 66 methods: 67 # use the first one on the client 68 #"go" usebundle => appgroups($(sys.uqhost), @(groups)); 69 "go" usebundle => appgroups("Host1", @(groups)); 70 "go" usebundle => appgroups("Host2", @(groups)); 71} 72 73bundle agent appgroups(name, g) 74{ 75 classes: 76 # stage (3) now for each APP, define have_app_APP if the host is in APP's host list 77 "have_app_$(apps)" expression => strcmp($(name), "$(hosts_$(apps))"); 78 79 # stage (4) define the class have_group_GROUP for every GROUP belonging to APP 80 "have_group_$(groups_$(apps))" expression => "have_app_$(apps)"; 81 82 # stage (5) define the class have_group if we found any groups 83 "have_group" not => strcmp("0", length("$(cname)_list")); 84 85 vars: 86 # stage (1) start here: we get the apps from the list of "by app" keys 87 "apps" slist => getindices("g[ByApp]"); 88 "apps_str" string => format("%S", "apps"); 89 # stage (2) now for each app, we collect the hosts assigned to it 90 "hosts_$(apps)" slist => getvalues("g[ByApp][$(apps)]"); 91 "hosts_$(apps)_str" string => format("%S", "hosts_$(apps)"); 92 93 # stage (2) now for each app, we collect the groups assigned to it 94 "groups_$(apps)" slist => getvalues("g[ByGroup][$(apps)]"); 95 "groups_$(apps)_str" string => format("%S", "groups_$(apps)"); 96 97 # stage (5) collect the space-separated group names from an intermediate array 98 "cname" string => canonify($(name)); 99 100 "$(cname)_grouplist[$(groups_$(apps))]" string => "1", 101 if => "have_app_$(apps)"; 102 103 "$(cname)_grouplist_slist" slist => getvalues("$(cname)_grouplist"); 104 105 # get the keys of the array and sort them, then join with spaces 106 "$(cname)_list" slist => getindices("$(cname)_grouplist"); 107 "$(cname)_list_sorted" slist => sort("$(cname)_list", "lex"); 108 "$(cname)_list_spaces" string => join(" ", "$(cname)_list_sorted"); 109 110 reports: 111 # stage (1) 112 "$(this.bundle): looking for $(name)"; 113 114 "$(this.bundle): apps: $(apps_str)"; 115 # stage (2) 116 "$(this.bundle): hosts for $(apps): $(hosts_$(apps)_str)"; 117 "$(this.bundle): groups for $(apps): $(groups_$(apps)_str)"; 118 119 # stage (3) 120 "$(this.bundle): $(name) is assigned $(apps)" 121 if => "have_app_$(apps)"; 122 123 # stage (4) 124 "$(this.bundle): all groups for $(name) = $(groups_$(apps))" 125 if => "have_group_$(groups_$(apps))"; 126 127 # stage (5) 128 have_group:: 129 "$(this.bundle): space-separated groups for $(name) = $($(cname)_list_spaces)"; 130} 131#+end_src 132############################################################################### 133#+begin_src example_output 134#@ ``` 135#@ R: appgroups: looking for Host1 136#@ R: appgroups: apps: { "App1", "App2" } 137#@ R: appgroups: hosts for App1: { "Host1", "Host2", "Host3" } 138#@ R: appgroups: hosts for App2: { "Host1", "Host3" } 139#@ R: appgroups: groups for App1: { "GrpA", "GrpB", "GrpC" } 140#@ R: appgroups: groups for App2: { "GrpX", "GrpY", "GrpZ" } 141#@ R: appgroups: Host1 is assigned App1 142#@ R: appgroups: Host1 is assigned App2 143#@ R: appgroups: all groups for Host1 = GrpA 144#@ R: appgroups: all groups for Host1 = GrpB 145#@ R: appgroups: all groups for Host1 = GrpC 146#@ R: appgroups: all groups for Host1 = GrpX 147#@ R: appgroups: all groups for Host1 = GrpY 148#@ R: appgroups: all groups for Host1 = GrpZ 149#@ R: appgroups: space-separated groups for Host1 = GrpA GrpB GrpC GrpX GrpY GrpZ 150#@ R: appgroups: looking for Host2 151#@ R: appgroups: Host2 is assigned App1 152#@ R: appgroups: all groups for Host2 = GrpA 153#@ R: appgroups: all groups for Host2 = GrpB 154#@ R: appgroups: all groups for Host2 = GrpC 155#@ R: appgroups: space-separated groups for Host2 = GrpA GrpB GrpC 156#@ ``` 157#+end_src 158