Add --uid-pool option to gnt-cluster init
[ganeti-local] / lib / uidpool.py
1 #
2 #
3
4 # Copyright (C) 2010 Google Inc.
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 2 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, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 # 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, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 # 02110-1301, USA.
20
21
22 """User-id pool related functions.
23
24 The user-id pool is cluster-wide configuration option.
25 It is stored as a list of user-id ranges.
26 This module contains functions used for manipulating the
27 user-id pool parameter and for requesting/returning user-ids
28 from the pool.
29
30 """
31
32 from ganeti import errors
33 from ganeti import constants
34 from ganeti import utils
35
36
37 def ParseUidPool(value, separator=None):
38   """Parse a user-id pool definition.
39
40   @param value: string representation of the user-id pool.
41                 The accepted input format is a list of integer ranges.
42                 The boundaries are inclusive.
43                 Example: '1000-5000,8000,9000-9010'.
44   @param separator: the separator character between the uids/uid-ranges.
45                     Defaults to a comma.
46   @return: a list of integer pairs (lower, higher range boundaries)
47
48   """
49   if separator is None:
50     separator = ","
51
52   ranges = []
53   for range_def in value.split(separator):
54     if not range_def:
55       # Skip empty strings
56       continue
57     boundaries = range_def.split("-")
58     n_elements = len(boundaries)
59     if n_elements > 2:
60       raise errors.OpPrereqError(
61           "Invalid user-id range definition. Only one hyphen allowed: %s"
62           % boundaries)
63     try:
64       lower = int(boundaries[0])
65     except (ValueError, TypeError), err:
66       raise errors.OpPrereqError("Invalid user-id value for lower boundary of"
67                                  " user-id range: %s"
68                                  % str(err), errors.ECODE_INVAL)
69     try:
70       higher = int(boundaries[n_elements - 1])
71     except (ValueError, TypeError), err:
72       raise errors.OpPrereqError("Invalid user-id value for higher boundary of"
73                                  " user-id range: %s"
74                                  % str(err), errors.ECODE_INVAL)
75
76     ranges.append((lower, higher))
77
78   ranges.sort()
79   return ranges
80
81
82 def AddToUidPool(uid_pool, add_uids):
83   """Add a list of user-ids/user-id ranges to a user-id pool.
84
85   @param uid_pool: a user-id pool (list of integer tuples)
86   @param add_uids: user-id ranges to be added to the pool
87                    (list of integer tuples)
88
89   """
90   for uid_range in add_uids:
91     if uid_range not in uid_pool:
92       uid_pool.append(uid_range)
93   uid_pool.sort()
94
95
96 def RemoveFromUidPool(uid_pool, remove_uids):
97   """Remove a list of user-ids/user-id ranges from a user-id pool.
98
99   @param uid_pool: a user-id pool (list of integer tuples)
100   @param remove_uids: user-id ranges to be removed from the pool
101                       (list of integer tuples)
102
103   """
104   for uid_range in remove_uids:
105     if uid_range not in uid_pool:
106       raise errors.OpPrereqError(
107           "User-id range to be removed is not found in the current"
108           " user-id pool: %s" % uid_range, errors.ECODE_INVAL)
109     uid_pool.remove(uid_range)
110
111
112 def _FormatUidRange(lower, higher):
113   """Convert a user-id range definition into a string.
114
115   """
116   if lower == higher:
117     return str(lower)
118   return "%s-%s" % (lower, higher)
119
120
121 def FormatUidPool(uid_pool):
122   """Convert the internal representation of the user-id pool into a string.
123
124   The output format is also accepted by ParseUidPool()
125
126   @param uid_pool: a list of integer pairs representing UID ranges
127   @return: a string with the formatted results
128
129   """
130   return utils.CommaJoin([_FormatUidRange(lower, higher)
131                           for lower, higher in uid_pool])
132
133
134 def CheckUidPool(uid_pool):
135   """Sanity check user-id pool range definition values.
136
137   @param uid_pool: a list of integer pairs (lower, higher range boundaries)
138
139   """
140   for lower, higher in uid_pool:
141     if lower > higher:
142       raise errors.OpPrereqError(
143           "Lower user-id range boundary value (%s)"
144           " is larger than higher boundary value (%s)" %
145           (lower, higher), errors.ECODE_INVAL)
146     if lower < constants.UIDPOOL_UID_MIN:
147       raise errors.OpPrereqError(
148           "Lower user-id range boundary value (%s)"
149           " is smaller than UIDPOOL_UID_MIN (%s)." %
150           (lower, constants.UIDPOOL_UID_MIN),
151           errors.ECODE_INVAL)
152     if higher > constants.UIDPOOL_UID_MAX:
153       raise errors.OpPrereqError(
154           "Higher user-id boundary value (%s)"
155           " is larger than UIDPOOL_UID_MAX (%s)." %
156           (higher, constants.UIDPOOL_UID_MAX),
157           errors.ECODE_INVAL)
158
159
160 def ExpandUidPool(uid_pool):
161   """Expands a uid-pool definition to a list of uids.
162
163   @param uid_pool: a list of integer pairs (lower, higher range boundaries)
164   @return: a list of integers
165
166   """
167   uids = set()
168   for lower, higher in uid_pool:
169     uids.update(range(lower, higher + 1))
170   return list(uids)