Use 'DTS_LVM' when possible
[ganeti-local] / lib / utils / storage.py
1 #
2 #
3
4 # Copyright (C) 2013 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 """Utility functions for storage.
22
23 """
24
25 import logging
26
27 from ganeti import constants
28
29
30 def GetDiskTemplatesOfStorageType(storage_type):
31   """Given the storage type, returns a list of disk templates based on that
32      storage type."""
33   return [dt for dt in constants.DISK_TEMPLATES
34           if constants.MAP_DISK_TEMPLATE_STORAGE_TYPE[dt] == storage_type]
35
36
37 def IsDiskTemplateEnabled(disk_template, enabled_disk_templates):
38   """Checks if a particular disk template is enabled.
39
40   """
41   return disk_template in enabled_disk_templates
42
43
44 def IsFileStorageEnabled(enabled_disk_templates):
45   """Checks if file storage is enabled.
46
47   """
48   return IsDiskTemplateEnabled(constants.DT_FILE, enabled_disk_templates)
49
50
51 def IsSharedFileStorageEnabled(enabled_disk_templates):
52   """Checks if shared file storage is enabled.
53
54   """
55   return IsDiskTemplateEnabled(constants.DT_SHARED_FILE, enabled_disk_templates)
56
57
58 def IsLvmEnabled(enabled_disk_templates):
59   """Check whether or not any lvm-based disk templates are enabled."""
60   return len(constants.DTS_LVM & set(enabled_disk_templates)) != 0
61
62
63 def LvmGetsEnabled(enabled_disk_templates, new_enabled_disk_templates):
64   """Checks whether lvm was not enabled before, but will be enabled after
65      the operation.
66
67   """
68   if IsLvmEnabled(enabled_disk_templates):
69     return False
70   return len(constants.DTS_LVM & set(new_enabled_disk_templates)) != 0
71
72
73 def _GetDefaultStorageUnitForDiskTemplate(cfg, disk_template):
74   """Retrieves the identifier of the default storage entity for the given
75   storage type.
76
77   @type cfg: C{objects.ConfigData}
78   @param cfg: the configuration data
79   @type disk_template: string
80   @param disk_template: a disk template, for example 'drbd'
81   @rtype: string
82   @return: identifier for a storage unit, for example the vg_name for lvm
83      storage
84
85   """
86   storage_type = constants.MAP_DISK_TEMPLATE_STORAGE_TYPE[disk_template]
87   cluster = cfg.GetClusterInfo()
88   if disk_template in constants.DTS_LVM:
89     return (storage_type, cfg.GetVGName())
90   elif disk_template == constants.DT_FILE:
91     return (storage_type, cluster.file_storage_dir)
92   elif disk_template == constants.DT_SHARED_FILE:
93     return (storage_type, cluster.shared_file_storage_dir)
94   else:
95     return (storage_type, None)
96
97
98 def _GetDefaultStorageUnitForSpindles(cfg):
99   """Creates a 'spindle' storage unit, by retrieving the volume group
100   name and associating it to the lvm-pv storage type.
101
102   @rtype: (string, string)
103   @return: tuple (storage_type, storage_key), where storage type is
104     'lvm-pv' and storage_key the name of the default volume group
105
106   """
107   return (constants.ST_LVM_PV, cfg.GetVGName())
108
109
110 def GetStorageUnitsOfCluster(cfg, include_spindles=False):
111   """Examines the cluster's configuration and returns a list of storage
112   units and their storage keys, ordered by the order in which they
113   are enabled.
114
115   @type cfg: L{config.ConfigWriter}
116   @param cfg: Cluster configuration
117   @type include_spindles: boolean
118   @param include_spindles: flag to include an extra storage unit for physical
119     volumes
120   @rtype: list of tuples (string, string)
121   @return: list of storage units, each storage unit being a tuple of
122     (storage_type, storage_key); storage_type is in
123     C{constants.STORAGE_TYPES} and the storage_key a string to
124     identify an entity of that storage type, for example a volume group
125     name for LVM storage or a file for file storage.
126
127   """
128   cluster_config = cfg.GetClusterInfo()
129   storage_units = []
130   for disk_template in cluster_config.enabled_disk_templates:
131     if constants.MAP_DISK_TEMPLATE_STORAGE_TYPE[disk_template]\
132         in constants.STS_REPORT:
133       storage_units.append(
134           _GetDefaultStorageUnitForDiskTemplate(cfg, disk_template))
135   if include_spindles:
136     included_storage_types = set([st for (st, _) in storage_units])
137     if not constants.ST_LVM_PV in included_storage_types:
138       storage_units.append(
139           _GetDefaultStorageUnitForSpindles(cfg))
140
141   return storage_units
142
143
144 def GetStorageUnits(cfg, disk_templates):
145   """Get the cluster's storage units for the given disk templates.
146
147   If any lvm-based disk template is requested, spindle information
148   is added to the request.
149
150   @type cfg: L{config.ConfigWriter}
151   @param cfg: Cluster configuration
152   @type disk_templates: list of string
153   @param disk_templates: list of disk templates for which the storage
154     units will be computed
155   @rtype: list of tuples (string, string)
156   @return: list of storage units, each storage unit being a tuple of
157     (storage_type, storage_key); storage_type is in
158     C{constants.STORAGE_TYPES} and the storage_key a string to
159     identify an entity of that storage type, for example a volume group
160     name for LVM storage or a file for file storage.
161
162   """
163   storage_units = []
164   for disk_template in disk_templates:
165     if constants.MAP_DISK_TEMPLATE_STORAGE_TYPE[disk_template]\
166         in constants.STS_REPORT:
167       storage_units.append(
168           _GetDefaultStorageUnitForDiskTemplate(cfg, disk_template))
169   if len(set(disk_templates) & constants.DTS_LVM) > 0:
170     storage_units.append(
171         _GetDefaultStorageUnitForSpindles(cfg))
172
173   return storage_units
174
175
176 def LookupSpaceInfoByDiskTemplate(storage_space_info, disk_template):
177   """Looks up the storage space info for a given disk template.
178
179   @type storage_space_info: list of dicts
180   @param storage_space_info: result of C{GetNodeInfo}
181   @type disk_template: string
182   @param disk_template: disk template to get storage space info
183   @rtype: tuple
184   @return: returns the element of storage_space_info that matches the given
185     disk template
186
187   """
188   storage_type = constants.MAP_DISK_TEMPLATE_STORAGE_TYPE[disk_template]
189   return LookupSpaceInfoByStorageType(storage_space_info, storage_type)
190
191
192 def LookupSpaceInfoByStorageType(storage_space_info, storage_type):
193   """Looks up the storage space info for a given storage type.
194
195   Note that this lookup can be ambiguous if storage space reporting for several
196   units of the same storage type was requested. This function is only supposed
197   to be used for legacy code in situations where it actually is unambiguous.
198
199   @type storage_space_info: list of dicts
200   @param storage_space_info: result of C{GetNodeInfo}
201   @type storage_type: string
202   @param storage_type: a storage type, which is included in the storage_units
203     list
204   @rtype: tuple
205   @return: returns the element of storage_space_info that matches the given
206     storage type
207
208   """
209   result = None
210   for unit_info in storage_space_info:
211     if unit_info["type"] == storage_type:
212       if result is None:
213         result = unit_info
214       else:
215         # There is more than one storage type in the query, log a warning
216         logging.warning("Storage space information requested for"
217                         " ambiguous storage type '%s'.", storage_type)
218   return result