File: nodesets.rst

package info (click to toggle)
clustershell 1.9.3-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,228 kB
  • sloc: python: 20,978; makefile: 149
file content (321 lines) | stat: -rw-r--r-- 10,733 bytes parent folder | download | duplicates (2)
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
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
.. _guide-NodeSet:

Node sets handling
==================

.. highlight:: python

.. _class-NodeSet:

NodeSet class
-------------

:class:`.NodeSet` is a class to represent an ordered set of node names
(optionally indexed). It's a convenient way to deal with cluster nodes and
ease their administration. :class:`.NodeSet` is implemented with the help of
two other ClusterShell public classes, :class:`.RangeSet` and
:class:`.RangeSetND`, which implement methods to manage a set of numeric
ranges in one or multiple dimensions. :class:`.NodeSet`, :class:`.RangeSet`
and :class:`.RangeSetND` APIs match standard Python sets.  A command-line
interface (:ref:`nodeset-tool`) which implements most of :class:`.NodeSet`
features, is also available.

Other classes of the ClusterShell library makes use of the :class:`.NodeSet`
class when they come to deal with distant nodes.

Using NodeSet
^^^^^^^^^^^^^

If you are used to `Python sets`_, :class:`.NodeSet` interface will be easy
for you to learn. The main conceptual difference is that :class:`.NodeSet`
iterators always provide ordered results (and also
:meth:`.NodeSet.__getitem__()` by index or slice is allowed). Furthermore,
:class:`.NodeSet` provides specific methods like
:meth:`.NodeSet.split()`, :meth:`.NodeSet.contiguous()` (see below), or
:meth:`.NodeSet.groups()`, :meth:`.NodeSet.regroup()` (these last two are
related to :ref:`class-NodeSet-groups`). The following code snippet shows you
a basic usage of the :class:`.NodeSet` class::

    >>> from ClusterShell.NodeSet import NodeSet
    >>> nodeset = NodeSet()
    >>> nodeset.add("node7")
    >>> nodeset.add("node6")
    >>> print nodeset
    node[6-7]

:class:`.NodeSet` class provides several object constructors::

    >>> print NodeSet("node[1-5]")
    node[1-5]
    >>> print NodeSet.fromlist(["node1", "node2", "node3"])
    node[1-3]
    >>> print NodeSet.fromlist(["node[1-5]", "node[6-10]"])
    node[1-10]
    >>> print NodeSet.fromlist(["clu-1-[1-4]", "clu-2-[1-4]"])
    clu-[1-2]-[1-4]

All corresponding Python sets operations are available, for example::

    >>> from ClusterShell.NodeSet import NodeSet
    >>> ns1 = NodeSet("node[10-42]")
    >>> ns2 = NodeSet("node[11-16,18-39]")
    >>> print ns1.difference(ns2)
    node[10,17,40-42]
    >>> print ns1 - ns2
    node[10,17,40-42]
    >>> ns3 = NodeSet("node[1-14,40-200]")
    >>> print ns3.intersection(ns1)
    node[10-14,40-42]


Unlike Python sets, it is important to notice that :class:`.NodeSet` is
somewhat not so strict about the type of element used for set operations. Thus
when a string object is encountered, it is automatically converted to a
NodeSet object for convenience. The following example shows an example of
this (set operation is working with either a native nodeset or a string)::

    >>> nodeset = NodeSet("node[1-10]")
    >>> nodeset2 = NodeSet("node7")
    >>> nodeset.difference_update(nodeset2)
    >>> print nodeset
    node[1-6,8-10]
    >>> 
    >>> nodeset.difference_update("node8")
    >>> print nodeset
    node[1-6,9-10]

NodeSet ordered content leads to the following being allowed::

    >>> nodeset = NodeSet("node[10-49]")
    >>> print nodeset[0]
    node10
    >>> print nodeset[-1]
    node49
    >>> print nodeset[10:]
    node[20-49]
    >>> print nodeset[:5]
    node[10-14]
    >>> print nodeset[::4]
    node[10,14,18,22,26,30,34,38,42,46]

And it works for node names without index, for example::

    >>> nodeset = NodeSet("lima,oscar,zulu,alpha,delta,foxtrot,tango,x-ray")
    >>> print nodeset
    alpha,delta,foxtrot,lima,oscar,tango,x-ray,zulu
    >>> print nodeset[0]
    alpha
    >>> print nodeset[-2]
    x-ray

And also for multidimensional node sets::

    >>> nodeset = NodeSet("clu1-[1-10]-ib[0-1],clu2-[1-10]-ib[0-1]")
    >>> print nodeset
    clu[1-2]-[1-10]-ib[0-1]
    >>> print nodeset[0]
    clu1-1-ib0
    >>> print nodeset[-1]
    clu2-10-ib1
    >>> print nodeset[::2]
    clu[1-2]-[1-10]-ib0

.. _class-NodeSet-split:

To split a NodeSet object into *n* subsets, use the :meth:`.NodeSet.split()`
method, for example::

    >>> for nodeset in NodeSet("node[10-49]").split(2):
    ...     print nodeset
    ... 
    node[10-29]
    node[30-49]

.. _class-NodeSet-contiguous:

To split a NodeSet object into contiguous subsets, use the
:meth:`.NodeSet.contiguous()` method, for example::

    >>> for nodeset in NodeSet("node[10-49,51-53,60-64]").contiguous():
    ...     print nodeset
    ... 
    node[10-49]
    node[51-53]
    node[60-64]

For further details, please use the following command to see full
:class:`.NodeSet` API documentation.


.. _class-NodeSet-nD:

Multidimensional considerations
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Version 1.7 introduces full support of multidimensional NodeSet (eg.
*da[2-5]c[1-2]p[0-1]*). The :class:`.NodeSet` interface is the same,
multidimensional patterns are automatically detected by the parser and
processed internally. While expanding a multidimensional NodeSet is easily
solved by performing a cartesian product of all dimensions, folding nodes is
much more complex and time consuming. To reduce the performance impact of such
feature, the :class:`.NodeSet` class still relies on :class:`.RangeSet` when
only one dimension is varying (see :ref:`class-RangeSet`).  Otherwise, it uses
a new class named :class:`.RangeSetND` for full multidimensional support (see
:ref:`class-RangeSetND`).

.. _class-NodeSet-extended-patterns:

Extended String Pattern
^^^^^^^^^^^^^^^^^^^^^^^

:class:`.NodeSet` class parsing engine recognizes an *extended string
pattern*, adding support for union (with special character *","*), difference
(with special character *"!"*), intersection (with special character *"&"*)
and symmetric difference (with special character *"^"*) operations. String
patterns are read from left to right, by proceeding any character operators
accordingly. The following example shows how you can use this feature::

    >>> print NodeSet("node[10-42],node46!node10")
    node[11-42,46]


.. _class-NodeSet-groups:

Node groups
-----------

Node groups are very useful and are needed to group similar cluster nodes in
terms of configuration, installed software, available resources, etc. A node
can be a member of more than one node group.

Using node groups
^^^^^^^^^^^^^^^^^

Node groups are prefixed with **@** character. Please see
:ref:`nodeset-groupsexpr` for more details about node group expression/syntax
rules.

Please also have a look at :ref:`Node groups configuration <groups-config>` to
learn how to configure external node group bingings (sources). Once setup
(please use the :ref:`nodeset-tool` command to check your configuration), the
NodeSet parsing engine automatically resolves node groups. For example::

    >>> print NodeSet("@oss")
    example[4-5]
    >>> print NodeSet("@compute")
    example[32-159]
    >>> print NodeSet("@compute,@oss")
    example[4-5,32-159]

That is, all NodeSet-based applications share the same system-wide node group
configuration (unless explicitly disabled --- see
:ref:`class-NodeSet-disable-group`).

When the **all** group upcall is configured (:ref:`node groups configuration
<groups-config>`), you can also use the following :class:`.NodeSet`
constructor::

    >>> print NodeSet.fromall()
    example[4-6,32-159]

When group upcalls are not properly configured, this constructor will raise a
*NodeSetExternalError* exception.

.. _class-NodeSet-groups-finding:

Finding node groups
^^^^^^^^^^^^^^^^^^^

In order to find node groups a specified node set belongs to, you can use the
:meth:`.NodeSet.groups()` method. This method is used by ``nodeset -l
<nodeset>`` command (see :ref:`nodeset-group-finding`). It returns a Python
dictionary where keys are groups found and values, provided for convenience,
are tuples of the form *(group_nodeset, contained_nodeset)*. For example::

    >>> for group, (group_nodes, contained_nodes) in NodeSet("@oss").groups().iteritems():
    ...     print group, group_nodes, contained_nodes
    ... 
    @all example[4-6,32-159] example[4-5]
    @oss example[4-5] example[4-5]


More usage examples follow::

    >>> print NodeSet("example4").groups().keys()
    ['@all', '@oss']
    >>> print NodeSet("@mds").groups().keys()
    ['@all', '@mds']
    >>> print NodeSet("dummy0").groups().keys()
    []

.. _class-NodeSet-regroup:

Regrouping node sets
^^^^^^^^^^^^^^^^^^^^

If needed group configuration conditions are met (cf. :ref:`node groups
configuration <groups-config>`), you can use the :meth:`.NodeSet.regroup()`
method to reduce node sets using matching groups, whenever possible::

    >>> print NodeSet("example[4-6]").regroup()
    @mds,@oss

The nodeset command makes use of the :meth:`.NodeSet.regroup()` method when
using the *-r* switch (see :ref:`nodeset-regroup`).


.. _class-NodeSet-groups-override:

Overriding default groups configuration
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

It is possible to override the library default groups configuration by
changing the default :class:`.NodeSet` *resolver* object. Usually, this is
done for testing or special purposes. Here is an example of how to override
the *resolver* object using :func:`.NodeSet.set_std_group_resolver()` in order
to use another configuration file::

    >>> from ClusterShell.NodeSet import NodeSet, set_std_group_resolver
    >>> from ClusterShell.NodeUtils import GroupResolverConfig
    >>> set_std_group_resolver(GroupResolverConfig("/other/groups.conf"))
    >>> print NodeSet("@oss")
    other[10-20]

It is possible to restore :class:`.NodeSet` *default group resolver* by
passing None to the :func:`.NodeSet.set_std_group_resolver()` module function,
for example::

    >>> from ClusterShell.NodeSet import set_std_group_resolver
    >>> set_std_group_resolver(None)


.. _class-NodeSet-disable-group:

Disabling node group resolution
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

If for any reason, you want to disable host groups resolution, you can use the
special resolver value *RESOLVER_NOGROUP*. In that case, :class:`.NodeSet`
parsing engine will not recognize **@** group characters anymore, for
instance::

    >>> from ClusterShell.NodeSet import NodeSet, RESOLVER_NOGROUP
    >>> print NodeSet("@oss")
    example[4-5]
    >>> print NodeSet("@oss", resolver=RESOLVER_NOGROUP)
    @oss

Any attempts to use a group-based method (like :meth:`.NodeSet.groups()` or
:meth:`.NodeSet.regroups()`) on such "no group" NodeSet will raise a
*NodeSetExternalError* exception.


NodeSet object serialization
----------------------------

The :class:`.NodeSet` class supports object serialization through the standard
*pickling*. Group resolution is done before *pickling*.



.. _Python sets: http://docs.python.org/library/sets.html