This file is indexed.

/usr/share/pyshared/cts/CIB.py is in pacemaker 1.1.7-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
'''CTS: Cluster Testing System: CIB generator
'''
__copyright__='''
Author: Andrew Beekhof <abeekhof@suse.de>
Copyright (C) 2008 Andrew Beekhof
'''

from UserDict import UserDict
import sys, time, types, syslog, os, struct, string, signal, traceback, warnings, socket

from cts.CTSvars import *
from cts.CTS     import ClusterManager

class CibBase:
    cts_cib = None
    cib_tmpfile = None
    version = "unknown"
    feature_set = "unknown"
    target = None

    def __init__(self, CM, tmpfile=None):
        self.CM = CM
        #self.target = self.CM.Env["nodes"][0]

        if not tmpfile:
            warnings.filterwarnings("ignore")
            self.cib_tmpfile=os.tmpnam()
            warnings.resetwarnings()
        else:
            self.cib_tmpfile = tmpfile

    def version(self):
        return self.version

    def NextIP(self):
        fields = string.split(self.CM.Env["IPBase"], '.')
        fields[3] = str(int(fields[3])+1)
        ip = string.join(fields, '.')
        self.CM.Env["IPBase"] = ip
        return ip

class CIB10(CibBase):
    feature_set = "3.0"
    version = "pacemaker-1.0"
    cib_template = '''
<cib crm_feature_set='%s' admin_epoch='1' epoch='0' num_updates='0' validate-with='%s' %s>
   <configuration>
      <crm_config/>
      <nodes/>
      <resources/>
      <constraints/>
   </configuration>
   <status/>
</cib>'''

    def _create(self, command):
        fixed = "HOME=/root CIB_file="+self.cib_tmpfile+" crm --force configure " + command 
        rc = self.CM.rsh(self.target, fixed)
        if rc != 0:
            self.CM.log("Configure call failed: "+fixed)
            sys.exit(1)

    def _show(self, command=""):
        output = ""
        (rc, result) = self.CM.rsh(self.target, "HOME=/root CIB_file="+self.cib_tmpfile+" crm configure show "+command, None, )
        for line in result:
            output += line
            self.CM.debug("Generated Config: "+line)
        return output

    def NewIP(self, name=None, standard="ocf:heartbeat"):
        ip = self.NextIP()
        if not name:
            name = "r"+ip

        if not standard:
            standard = ""
        else:
            standard += ":"

        self._create('''primitive %s %sIPaddr params ip=%s cidr_netmask=32 op monitor interval=5s''' 
                  % (name, standard, ip))
        return name

    def install(self, target):
        old = self.cib_tmpfile

        # Force a rebuild
        self.cts_cib = None

        self.cib_tmpfile = CTSvars.CRM_CONFIG_DIR+"/cib.xml"
        self.contents(target)
        self.CM.rsh(self.target, "chown "+CTSvars.CRM_DAEMON_USER+" "+self.cib_tmpfile)

        self.cib_tmpfile = old

    def contents(self, target=None):
        # fencing resource
        if self.cts_cib:
            return self.cts_cib
        
        if not target:
            self.target = self.CM.Env["nodes"][0]
        else:
            self.target = target

        cib_base = self.cib_template % (self.feature_set, self.version, ''' remote-tls-port='9898' remote-clear-port='9999' ''')
        self.CM.rsh(self.target, '''echo "%s" > %s''' % (cib_base, self.cib_tmpfile))
        #self.CM.rsh.cp(self.cib_tmpfile, "root@%s:%s" % (self.target, self.cib_tmpfile))

        nodelist = ""
        self.num_nodes = 0
        for node in self.CM.Env["nodes"]:
            nodelist += node + " "
            self.num_nodes = self.num_nodes + 1

        no_quorum = "stop"
        if self.num_nodes < 3:
            no_quorum = "ignore"
            self.CM.log("Cluster only has %d nodes, configuring: no-quroum-policy=ignore" % self.num_nodes) 


        # The shell no longer functions when the lrmd isn't running, how wonderful
        # Start one here and let the cluster clean it up when the full stack starts
        # Just hope target has the same location for lrmd
        self.CM.rsh(self.target, CTSvars.CRM_DAEMON_DIR+"/lrmd", synchronous=0)

        # Tell the shell to mind its own business, we know what we're doing
        self.CM.rsh(self.target, "crm options check-mode relaxed")

        # Fencing resource
        # Define first so that the shell doesn't reject every update
        if self.CM.Env["DoFencing"]:
            params = None
            entries = string.split(self.CM.Env["stonith-params"], ',')
            for entry in entries:
                (name, value) = string.split(entry, '=')
                if name == "hostlist" and value == "all":
                    value = string.join(self.CM.Env["nodes"], " ")

                if params:
                    params = ("""%s '%s="%s"' """ % (params, name, value))
                else:
                    params = ("""'%s="%s"' """ % (name, value))

            if params:
                params = "params %s" % params
            else:
                params = ""

            # Set a threshold for unreliable stonith devices such as the vmware one
            self._create('''primitive Fencing stonith::%s %s meta migration-threshold=5 op monitor interval=120s timeout=300 op start interval=0 timeout=180s op stop interval=0 timeout=180s''' % (self.CM.Env["stonith-type"], params))

        self._create('''property stonith-enabled=%s''' % (self.CM.Env["DoFencing"]))
        self._create('''property start-failure-is-fatal=false pe-input-series-max=5000 default-action-timeout=60s''')
        self._create('''property shutdown-escalation=5min batch-limit=10 dc-deadtime=5s''')
        self._create('''property no-quorum-policy=%s expected-quorum-votes=%d''' % (no_quorum, self.num_nodes))

        if self.CM.Env["DoBSC"] == 1:
            self._create('''property ident-string="Linux-HA TEST configuration file - REMOVEME!!"''')

        # Add resources?
        if self.CM.Env["CIBResource"] == 1:
            self.add_resources()

        if self.CM.cluster_monitor == 1:
            self._create('''primitive cluster_mon ocf:pacemaker:ClusterMon params update=10 extra_options="-r -n" user=abeekhof htmlfile=/suse/abeekhof/Export/cluster.html op start interval=0 requires=nothing op monitor interval=5s requires=nothing''')
            self._create('''location prefer-dc cluster_mon rule -INFINITY: \#is_dc eq false''')

        # generate cib
        self.cts_cib = self._show("xml")

        if self.cib_tmpfile != CTSvars.CRM_CONFIG_DIR+"/cib.xml":
            self.CM.rsh(self.target, "rm -f "+self.cib_tmpfile)

        return self.cts_cib

    def add_resources(self):
        # Group Resource
        r1 = self.NewIP()
        #ip = self.NextIP()
        #r2 = "r"+ip
        #self._create('''primitive %s heartbeat::IPaddr params 1=%s/32 op monitor interval=5s''' % (r2, ip))
        r2 = self.NewIP()
        r3 = self.NewIP()
        self._create('''group group-1 %s %s %s''' % (r1, r2, r3))

        # Per-node resources
        for node in self.CM.Env["nodes"]:
            r = self.NewIP("rsc_"+node)
            self._create('''location prefer-%s %s rule 100: \#uname eq %s''' % (node, r, node))
                
        # LSB resource
        lsb_agent = self.CM.install_helper("LSBDummy")
    
        self._create('''primitive lsb-dummy lsb::''' +lsb_agent+ ''' op monitor interval=5s''')
        self._create('''colocation lsb-with-group INFINITY: lsb-dummy group-1''')
        self._create('''order lsb-after-group mandatory: group-1 lsb-dummy symmetrical=true''')

        # Migrator
        # Make this slightly sticky (since we have no other location constraints) to avoid relocation during Reattach 
        self._create('''primitive migrator ocf:pacemaker:Dummy meta resource-stickiness=1 allow-migrate=1 op monitor interval=P10S''')

        # Ping the test master
        self._create('''primitive ping-1 ocf:pacemaker:ping params host_list=%s name=connected debug=true op monitor interval=60s''' % self.CM.Env["cts-master"])
        self._create('''clone Connectivity ping-1 meta globally-unique=false''')

        #master slave resource
        self._create('''primitive stateful-1 ocf:pacemaker:Stateful op monitor interval=15s timeout=60s op monitor interval=16s role=Master timeout=60s ''')
        self._create('''ms master-1 stateful-1 meta clone-max=%d clone-node-max=%d master-max=%d master-node-max=%d'''
                     % (self.num_nodes, 1, 1, 1))

        # Require conectivity to run the master
        self._create('''location %s-is-connected %s rule -INFINITY: connected lt %d or not_defined connected''' % ("m1", "master-1", 1))

        # Group with the master
        self._create('''colocation group-with-master INFINITY: group-1 master-1:Master''')
        self._create('''order group-after-master mandatory: master-1:promote group-1:start symmetrical=true''')

class HASI(CIB10):
    def add_resources(self):
        # DLM resource
        self._create('''primitive dlm ocf:pacemaker:controld op monitor interval=120s''')
        self._create('''clone dlm-clone dlm meta globally-unique=false interleave=true''')

        # O2CB resource
        self._create('''primitive o2cb ocf:ocfs2:o2cb op monitor interval=120s''')
        self._create('''clone o2cb-clone o2cb meta globally-unique=false interleave=true''')
        self._create('''colocation o2cb-with-dlm INFINITY: o2cb-clone dlm-clone''')
        self._create('''order start-o2cb-after-dlm mandatory: dlm-clone o2cb-clone''')

class ConfigFactory:      
    def __init__(self, CM):
        self.CM = CM
        self.register("pacemaker10", CIB10, CM)
        self.register("hae", HASI, CM)


    def register(self, methodName, constructor, *args, **kargs):
        """register a constructor"""
        _args = [constructor]
        _args.extend(args)
        setattr(self, methodName, apply(ConfigFactoryItem,_args, kargs))
        
    def unregister(self, methodName):
        """unregister a constructor"""
        delattr(self, methodName)

    def createConfig(self, name="pacemaker-1.0"):
        if name == "pacemaker-1.0":
            name = "pacemaker10";
        elif name == "pacemaker-1.1":
            name = "pacemaker11";
        elif name == "pacemaker-1.2":
            name = "pacemaker12";
        elif name == "hasi":
            name = "hae";

        if hasattr(self, name):
            return getattr(self, name)()
        else:
            self.CM.log("Configuration variant '%s' is unknown.  Defaulting to latest config" % name)

        return self.pacemaker10()

class ConfigFactoryItem:
    def __init__(self, function, *args, **kargs):
        assert callable(function), "function should be a callable obj"
        self._function = function
        self._args = args
        self._kargs = kargs
        
    def __call__(self, *args, **kargs):
        """call function"""
        _args = list(self._args)
        _args.extend(args)
        _kargs = self._kargs.copy()
        _kargs.update(kargs)
        return apply(self._function,_args,_kargs)


#CibFactory = ConfigFactory()