root / lib / cmdlib / instance_query.py @ 2209788e
History | View | Annotate | Download (15 kB)
1 | 8aa8f6b1 | Thomas Thrainer | #
|
---|---|---|---|
2 | 8aa8f6b1 | Thomas Thrainer | #
|
3 | 8aa8f6b1 | Thomas Thrainer | |
4 | 8aa8f6b1 | Thomas Thrainer | # Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Google Inc.
|
5 | 8aa8f6b1 | Thomas Thrainer | #
|
6 | 8aa8f6b1 | Thomas Thrainer | # This program is free software; you can redistribute it and/or modify
|
7 | 8aa8f6b1 | Thomas Thrainer | # it under the terms of the GNU General Public License as published by
|
8 | 8aa8f6b1 | Thomas Thrainer | # the Free Software Foundation; either version 2 of the License, or
|
9 | 8aa8f6b1 | Thomas Thrainer | # (at your option) any later version.
|
10 | 8aa8f6b1 | Thomas Thrainer | #
|
11 | 8aa8f6b1 | Thomas Thrainer | # This program is distributed in the hope that it will be useful, but
|
12 | 8aa8f6b1 | Thomas Thrainer | # WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 | 8aa8f6b1 | Thomas Thrainer | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14 | 8aa8f6b1 | Thomas Thrainer | # General Public License for more details.
|
15 | 8aa8f6b1 | Thomas Thrainer | #
|
16 | 8aa8f6b1 | Thomas Thrainer | # You should have received a copy of the GNU General Public License
|
17 | 8aa8f6b1 | Thomas Thrainer | # along with this program; if not, write to the Free Software
|
18 | 8aa8f6b1 | Thomas Thrainer | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
19 | 8aa8f6b1 | Thomas Thrainer | # 02110-1301, USA.
|
20 | 8aa8f6b1 | Thomas Thrainer | |
21 | 8aa8f6b1 | Thomas Thrainer | |
22 | 8aa8f6b1 | Thomas Thrainer | """Logical units for querying instances."""
|
23 | 8aa8f6b1 | Thomas Thrainer | |
24 | 8aa8f6b1 | Thomas Thrainer | import itertools |
25 | 8aa8f6b1 | Thomas Thrainer | import logging |
26 | 8aa8f6b1 | Thomas Thrainer | import operator |
27 | 8aa8f6b1 | Thomas Thrainer | |
28 | 8aa8f6b1 | Thomas Thrainer | from ganeti import compat |
29 | 8aa8f6b1 | Thomas Thrainer | from ganeti import constants |
30 | 8aa8f6b1 | Thomas Thrainer | from ganeti import locking |
31 | 8aa8f6b1 | Thomas Thrainer | from ganeti import qlang |
32 | 8aa8f6b1 | Thomas Thrainer | from ganeti import query |
33 | 5eacbcae | Thomas Thrainer | from ganeti.cmdlib.base import QueryBase, NoHooksLU |
34 | 5eacbcae | Thomas Thrainer | from ganeti.cmdlib.common import ShareAll, GetWantedInstances, \ |
35 | 5eacbcae | Thomas Thrainer | CheckInstanceNodeGroups, CheckInstancesNodeGroups, AnnotateDiskParams |
36 | 5eacbcae | Thomas Thrainer | from ganeti.cmdlib.instance_operation import GetInstanceConsole |
37 | 5eacbcae | Thomas Thrainer | from ganeti.cmdlib.instance_utils import NICListToTuple |
38 | 8aa8f6b1 | Thomas Thrainer | |
39 | 8aa8f6b1 | Thomas Thrainer | import ganeti.masterd.instance |
40 | 8aa8f6b1 | Thomas Thrainer | |
41 | 8aa8f6b1 | Thomas Thrainer | |
42 | 5eacbcae | Thomas Thrainer | class InstanceQuery(QueryBase): |
43 | 8aa8f6b1 | Thomas Thrainer | FIELDS = query.INSTANCE_FIELDS |
44 | 8aa8f6b1 | Thomas Thrainer | |
45 | 8aa8f6b1 | Thomas Thrainer | def ExpandNames(self, lu): |
46 | 8aa8f6b1 | Thomas Thrainer | lu.needed_locks = {} |
47 | 5eacbcae | Thomas Thrainer | lu.share_locks = ShareAll() |
48 | 8aa8f6b1 | Thomas Thrainer | |
49 | 8aa8f6b1 | Thomas Thrainer | if self.names: |
50 | 5eacbcae | Thomas Thrainer | self.wanted = GetWantedInstances(lu, self.names) |
51 | 8aa8f6b1 | Thomas Thrainer | else:
|
52 | 8aa8f6b1 | Thomas Thrainer | self.wanted = locking.ALL_SET
|
53 | 8aa8f6b1 | Thomas Thrainer | |
54 | 8aa8f6b1 | Thomas Thrainer | self.do_locking = (self.use_locking and |
55 | 8aa8f6b1 | Thomas Thrainer | query.IQ_LIVE in self.requested_data) |
56 | 8aa8f6b1 | Thomas Thrainer | if self.do_locking: |
57 | 8aa8f6b1 | Thomas Thrainer | lu.needed_locks[locking.LEVEL_INSTANCE] = self.wanted
|
58 | 8aa8f6b1 | Thomas Thrainer | lu.needed_locks[locking.LEVEL_NODEGROUP] = [] |
59 | 8aa8f6b1 | Thomas Thrainer | lu.needed_locks[locking.LEVEL_NODE] = [] |
60 | 8aa8f6b1 | Thomas Thrainer | lu.needed_locks[locking.LEVEL_NETWORK] = [] |
61 | 8aa8f6b1 | Thomas Thrainer | lu.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_REPLACE |
62 | 8aa8f6b1 | Thomas Thrainer | |
63 | 8aa8f6b1 | Thomas Thrainer | self.do_grouplocks = (self.do_locking and |
64 | 8aa8f6b1 | Thomas Thrainer | query.IQ_NODES in self.requested_data) |
65 | 8aa8f6b1 | Thomas Thrainer | |
66 | 8aa8f6b1 | Thomas Thrainer | def DeclareLocks(self, lu, level): |
67 | 8aa8f6b1 | Thomas Thrainer | if self.do_locking: |
68 | 8aa8f6b1 | Thomas Thrainer | if level == locking.LEVEL_NODEGROUP and self.do_grouplocks: |
69 | 8aa8f6b1 | Thomas Thrainer | assert not lu.needed_locks[locking.LEVEL_NODEGROUP] |
70 | 8aa8f6b1 | Thomas Thrainer | |
71 | 8aa8f6b1 | Thomas Thrainer | # Lock all groups used by instances optimistically; this requires going
|
72 | 8aa8f6b1 | Thomas Thrainer | # via the node before it's locked, requiring verification later on
|
73 | 8aa8f6b1 | Thomas Thrainer | lu.needed_locks[locking.LEVEL_NODEGROUP] = \ |
74 | 8aa8f6b1 | Thomas Thrainer | set(group_uuid
|
75 | 8aa8f6b1 | Thomas Thrainer | for instance_name in lu.owned_locks(locking.LEVEL_INSTANCE) |
76 | 8aa8f6b1 | Thomas Thrainer | for group_uuid in lu.cfg.GetInstanceNodeGroups(instance_name)) |
77 | 8aa8f6b1 | Thomas Thrainer | elif level == locking.LEVEL_NODE:
|
78 | 8aa8f6b1 | Thomas Thrainer | lu._LockInstancesNodes() # pylint: disable=W0212
|
79 | 8aa8f6b1 | Thomas Thrainer | |
80 | 8aa8f6b1 | Thomas Thrainer | elif level == locking.LEVEL_NETWORK:
|
81 | 8aa8f6b1 | Thomas Thrainer | lu.needed_locks[locking.LEVEL_NETWORK] = \ |
82 | 8aa8f6b1 | Thomas Thrainer | frozenset(net_uuid
|
83 | 8aa8f6b1 | Thomas Thrainer | for instance_name in lu.owned_locks(locking.LEVEL_INSTANCE) |
84 | 8aa8f6b1 | Thomas Thrainer | for net_uuid in lu.cfg.GetInstanceNetworks(instance_name)) |
85 | 8aa8f6b1 | Thomas Thrainer | |
86 | 8aa8f6b1 | Thomas Thrainer | @staticmethod
|
87 | 8aa8f6b1 | Thomas Thrainer | def _CheckGroupLocks(lu): |
88 | 8aa8f6b1 | Thomas Thrainer | owned_instances = frozenset(lu.owned_locks(locking.LEVEL_INSTANCE))
|
89 | 8aa8f6b1 | Thomas Thrainer | owned_groups = frozenset(lu.owned_locks(locking.LEVEL_NODEGROUP))
|
90 | 8aa8f6b1 | Thomas Thrainer | |
91 | 8aa8f6b1 | Thomas Thrainer | # Check if node groups for locked instances are still correct
|
92 | 8aa8f6b1 | Thomas Thrainer | for instance_name in owned_instances: |
93 | 5eacbcae | Thomas Thrainer | CheckInstanceNodeGroups(lu.cfg, instance_name, owned_groups) |
94 | 8aa8f6b1 | Thomas Thrainer | |
95 | 8aa8f6b1 | Thomas Thrainer | def _GetQueryData(self, lu): |
96 | 8aa8f6b1 | Thomas Thrainer | """Computes the list of instances and their attributes.
|
97 | 8aa8f6b1 | Thomas Thrainer |
|
98 | 8aa8f6b1 | Thomas Thrainer | """
|
99 | 8aa8f6b1 | Thomas Thrainer | if self.do_grouplocks: |
100 | 8aa8f6b1 | Thomas Thrainer | self._CheckGroupLocks(lu)
|
101 | 8aa8f6b1 | Thomas Thrainer | |
102 | 8aa8f6b1 | Thomas Thrainer | cluster = lu.cfg.GetClusterInfo() |
103 | 8aa8f6b1 | Thomas Thrainer | all_info = lu.cfg.GetAllInstancesInfo() |
104 | 8aa8f6b1 | Thomas Thrainer | |
105 | 8aa8f6b1 | Thomas Thrainer | instance_names = self._GetNames(lu, all_info.keys(), locking.LEVEL_INSTANCE)
|
106 | 8aa8f6b1 | Thomas Thrainer | |
107 | 8aa8f6b1 | Thomas Thrainer | instance_list = [all_info[name] for name in instance_names] |
108 | 8aa8f6b1 | Thomas Thrainer | nodes = frozenset(itertools.chain(*(inst.all_nodes
|
109 | 8aa8f6b1 | Thomas Thrainer | for inst in instance_list))) |
110 | 8aa8f6b1 | Thomas Thrainer | hv_list = list(set([inst.hypervisor for inst in instance_list])) |
111 | 8aa8f6b1 | Thomas Thrainer | bad_nodes = [] |
112 | 8aa8f6b1 | Thomas Thrainer | offline_nodes = [] |
113 | 8aa8f6b1 | Thomas Thrainer | wrongnode_inst = set()
|
114 | 8aa8f6b1 | Thomas Thrainer | |
115 | 8aa8f6b1 | Thomas Thrainer | # Gather data as requested
|
116 | 8aa8f6b1 | Thomas Thrainer | if self.requested_data & set([query.IQ_LIVE, query.IQ_CONSOLE]): |
117 | 8aa8f6b1 | Thomas Thrainer | live_data = {} |
118 | 8aa8f6b1 | Thomas Thrainer | node_data = lu.rpc.call_all_instances_info(nodes, hv_list) |
119 | 8aa8f6b1 | Thomas Thrainer | for name in nodes: |
120 | 8aa8f6b1 | Thomas Thrainer | result = node_data[name] |
121 | 8aa8f6b1 | Thomas Thrainer | if result.offline:
|
122 | 8aa8f6b1 | Thomas Thrainer | # offline nodes will be in both lists
|
123 | 8aa8f6b1 | Thomas Thrainer | assert result.fail_msg
|
124 | 8aa8f6b1 | Thomas Thrainer | offline_nodes.append(name) |
125 | 8aa8f6b1 | Thomas Thrainer | if result.fail_msg:
|
126 | 8aa8f6b1 | Thomas Thrainer | bad_nodes.append(name) |
127 | 8aa8f6b1 | Thomas Thrainer | elif result.payload:
|
128 | 8aa8f6b1 | Thomas Thrainer | for inst in result.payload: |
129 | 8aa8f6b1 | Thomas Thrainer | if inst in all_info: |
130 | 8aa8f6b1 | Thomas Thrainer | if all_info[inst].primary_node == name:
|
131 | 8aa8f6b1 | Thomas Thrainer | live_data.update(result.payload) |
132 | 8aa8f6b1 | Thomas Thrainer | else:
|
133 | 8aa8f6b1 | Thomas Thrainer | wrongnode_inst.add(inst) |
134 | 8aa8f6b1 | Thomas Thrainer | else:
|
135 | 8aa8f6b1 | Thomas Thrainer | # orphan instance; we don't list it here as we don't
|
136 | 8aa8f6b1 | Thomas Thrainer | # handle this case yet in the output of instance listing
|
137 | 8aa8f6b1 | Thomas Thrainer | logging.warning("Orphan instance '%s' found on node %s",
|
138 | 8aa8f6b1 | Thomas Thrainer | inst, name) |
139 | 8aa8f6b1 | Thomas Thrainer | # else no instance is alive
|
140 | 8aa8f6b1 | Thomas Thrainer | else:
|
141 | 8aa8f6b1 | Thomas Thrainer | live_data = {} |
142 | 8aa8f6b1 | Thomas Thrainer | |
143 | 8aa8f6b1 | Thomas Thrainer | if query.IQ_DISKUSAGE in self.requested_data: |
144 | 8aa8f6b1 | Thomas Thrainer | gmi = ganeti.masterd.instance |
145 | 8aa8f6b1 | Thomas Thrainer | disk_usage = dict((inst.name,
|
146 | 8aa8f6b1 | Thomas Thrainer | gmi.ComputeDiskSize(inst.disk_template, |
147 | 8aa8f6b1 | Thomas Thrainer | [{constants.IDISK_SIZE: disk.size} |
148 | 8aa8f6b1 | Thomas Thrainer | for disk in inst.disks])) |
149 | 8aa8f6b1 | Thomas Thrainer | for inst in instance_list) |
150 | 8aa8f6b1 | Thomas Thrainer | else:
|
151 | 8aa8f6b1 | Thomas Thrainer | disk_usage = None
|
152 | 8aa8f6b1 | Thomas Thrainer | |
153 | 8aa8f6b1 | Thomas Thrainer | if query.IQ_CONSOLE in self.requested_data: |
154 | 8aa8f6b1 | Thomas Thrainer | consinfo = {} |
155 | 8aa8f6b1 | Thomas Thrainer | for inst in instance_list: |
156 | 8aa8f6b1 | Thomas Thrainer | if inst.name in live_data: |
157 | 8aa8f6b1 | Thomas Thrainer | # Instance is running
|
158 | 5eacbcae | Thomas Thrainer | consinfo[inst.name] = GetInstanceConsole(cluster, inst) |
159 | 8aa8f6b1 | Thomas Thrainer | else:
|
160 | 8aa8f6b1 | Thomas Thrainer | consinfo[inst.name] = None
|
161 | 8aa8f6b1 | Thomas Thrainer | assert set(consinfo.keys()) == set(instance_names) |
162 | 8aa8f6b1 | Thomas Thrainer | else:
|
163 | 8aa8f6b1 | Thomas Thrainer | consinfo = None
|
164 | 8aa8f6b1 | Thomas Thrainer | |
165 | 8aa8f6b1 | Thomas Thrainer | if query.IQ_NODES in self.requested_data: |
166 | 8aa8f6b1 | Thomas Thrainer | node_names = set(itertools.chain(*map(operator.attrgetter("all_nodes"), |
167 | 8aa8f6b1 | Thomas Thrainer | instance_list))) |
168 | 8aa8f6b1 | Thomas Thrainer | nodes = dict(lu.cfg.GetMultiNodeInfo(node_names))
|
169 | 8aa8f6b1 | Thomas Thrainer | groups = dict((uuid, lu.cfg.GetNodeGroup(uuid))
|
170 | 8aa8f6b1 | Thomas Thrainer | for uuid in set(map(operator.attrgetter("group"), |
171 | 8aa8f6b1 | Thomas Thrainer | nodes.values()))) |
172 | 8aa8f6b1 | Thomas Thrainer | else:
|
173 | 8aa8f6b1 | Thomas Thrainer | nodes = None
|
174 | 8aa8f6b1 | Thomas Thrainer | groups = None
|
175 | 8aa8f6b1 | Thomas Thrainer | |
176 | 8aa8f6b1 | Thomas Thrainer | if query.IQ_NETWORKS in self.requested_data: |
177 | 8aa8f6b1 | Thomas Thrainer | net_uuids = itertools.chain(*(lu.cfg.GetInstanceNetworks(i.name) |
178 | 8aa8f6b1 | Thomas Thrainer | for i in instance_list)) |
179 | 8aa8f6b1 | Thomas Thrainer | networks = dict((uuid, lu.cfg.GetNetwork(uuid)) for uuid in net_uuids) |
180 | 8aa8f6b1 | Thomas Thrainer | else:
|
181 | 8aa8f6b1 | Thomas Thrainer | networks = None
|
182 | 8aa8f6b1 | Thomas Thrainer | |
183 | 8aa8f6b1 | Thomas Thrainer | return query.InstanceQueryData(instance_list, lu.cfg.GetClusterInfo(),
|
184 | 8aa8f6b1 | Thomas Thrainer | disk_usage, offline_nodes, bad_nodes, |
185 | 8aa8f6b1 | Thomas Thrainer | live_data, wrongnode_inst, consinfo, |
186 | 8aa8f6b1 | Thomas Thrainer | nodes, groups, networks) |
187 | 8aa8f6b1 | Thomas Thrainer | |
188 | 8aa8f6b1 | Thomas Thrainer | |
189 | 8aa8f6b1 | Thomas Thrainer | class LUInstanceQuery(NoHooksLU): |
190 | 8aa8f6b1 | Thomas Thrainer | """Logical unit for querying instances.
|
191 | 8aa8f6b1 | Thomas Thrainer |
|
192 | 8aa8f6b1 | Thomas Thrainer | """
|
193 | 8aa8f6b1 | Thomas Thrainer | # pylint: disable=W0142
|
194 | 8aa8f6b1 | Thomas Thrainer | REQ_BGL = False
|
195 | 8aa8f6b1 | Thomas Thrainer | |
196 | 8aa8f6b1 | Thomas Thrainer | def CheckArguments(self): |
197 | 5eacbcae | Thomas Thrainer | self.iq = InstanceQuery(qlang.MakeSimpleFilter("name", self.op.names), |
198 | 8aa8f6b1 | Thomas Thrainer | self.op.output_fields, self.op.use_locking) |
199 | 8aa8f6b1 | Thomas Thrainer | |
200 | 8aa8f6b1 | Thomas Thrainer | def ExpandNames(self): |
201 | 8aa8f6b1 | Thomas Thrainer | self.iq.ExpandNames(self) |
202 | 8aa8f6b1 | Thomas Thrainer | |
203 | 8aa8f6b1 | Thomas Thrainer | def DeclareLocks(self, level): |
204 | 8aa8f6b1 | Thomas Thrainer | self.iq.DeclareLocks(self, level) |
205 | 8aa8f6b1 | Thomas Thrainer | |
206 | 8aa8f6b1 | Thomas Thrainer | def Exec(self, feedback_fn): |
207 | 8aa8f6b1 | Thomas Thrainer | return self.iq.OldStyleQuery(self) |
208 | 8aa8f6b1 | Thomas Thrainer | |
209 | 8aa8f6b1 | Thomas Thrainer | |
210 | 8aa8f6b1 | Thomas Thrainer | class LUInstanceQueryData(NoHooksLU): |
211 | 8aa8f6b1 | Thomas Thrainer | """Query runtime instance data.
|
212 | 8aa8f6b1 | Thomas Thrainer |
|
213 | 8aa8f6b1 | Thomas Thrainer | """
|
214 | 8aa8f6b1 | Thomas Thrainer | REQ_BGL = False
|
215 | 8aa8f6b1 | Thomas Thrainer | |
216 | 8aa8f6b1 | Thomas Thrainer | def ExpandNames(self): |
217 | 8aa8f6b1 | Thomas Thrainer | self.needed_locks = {}
|
218 | 8aa8f6b1 | Thomas Thrainer | |
219 | 8aa8f6b1 | Thomas Thrainer | # Use locking if requested or when non-static information is wanted
|
220 | 8aa8f6b1 | Thomas Thrainer | if not (self.op.static or self.op.use_locking): |
221 | 8aa8f6b1 | Thomas Thrainer | self.LogWarning("Non-static data requested, locks need to be acquired") |
222 | 8aa8f6b1 | Thomas Thrainer | self.op.use_locking = True |
223 | 8aa8f6b1 | Thomas Thrainer | |
224 | 8aa8f6b1 | Thomas Thrainer | if self.op.instances or not self.op.use_locking: |
225 | 8aa8f6b1 | Thomas Thrainer | # Expand instance names right here
|
226 | 5eacbcae | Thomas Thrainer | self.wanted_names = GetWantedInstances(self, self.op.instances) |
227 | 8aa8f6b1 | Thomas Thrainer | else:
|
228 | 8aa8f6b1 | Thomas Thrainer | # Will use acquired locks
|
229 | 8aa8f6b1 | Thomas Thrainer | self.wanted_names = None |
230 | 8aa8f6b1 | Thomas Thrainer | |
231 | 8aa8f6b1 | Thomas Thrainer | if self.op.use_locking: |
232 | 5eacbcae | Thomas Thrainer | self.share_locks = ShareAll()
|
233 | 8aa8f6b1 | Thomas Thrainer | |
234 | 8aa8f6b1 | Thomas Thrainer | if self.wanted_names is None: |
235 | 8aa8f6b1 | Thomas Thrainer | self.needed_locks[locking.LEVEL_INSTANCE] = locking.ALL_SET
|
236 | 8aa8f6b1 | Thomas Thrainer | else:
|
237 | 8aa8f6b1 | Thomas Thrainer | self.needed_locks[locking.LEVEL_INSTANCE] = self.wanted_names |
238 | 8aa8f6b1 | Thomas Thrainer | |
239 | 8aa8f6b1 | Thomas Thrainer | self.needed_locks[locking.LEVEL_NODEGROUP] = []
|
240 | 8aa8f6b1 | Thomas Thrainer | self.needed_locks[locking.LEVEL_NODE] = []
|
241 | 8aa8f6b1 | Thomas Thrainer | self.needed_locks[locking.LEVEL_NETWORK] = []
|
242 | 8aa8f6b1 | Thomas Thrainer | self.recalculate_locks[locking.LEVEL_NODE] = constants.LOCKS_REPLACE
|
243 | 8aa8f6b1 | Thomas Thrainer | |
244 | 8aa8f6b1 | Thomas Thrainer | def DeclareLocks(self, level): |
245 | 8aa8f6b1 | Thomas Thrainer | if self.op.use_locking: |
246 | 8aa8f6b1 | Thomas Thrainer | owned_instances = self.owned_locks(locking.LEVEL_INSTANCE)
|
247 | 8aa8f6b1 | Thomas Thrainer | if level == locking.LEVEL_NODEGROUP:
|
248 | 8aa8f6b1 | Thomas Thrainer | |
249 | 8aa8f6b1 | Thomas Thrainer | # Lock all groups used by instances optimistically; this requires going
|
250 | 8aa8f6b1 | Thomas Thrainer | # via the node before it's locked, requiring verification later on
|
251 | 8aa8f6b1 | Thomas Thrainer | self.needed_locks[locking.LEVEL_NODEGROUP] = \
|
252 | 8aa8f6b1 | Thomas Thrainer | frozenset(group_uuid
|
253 | 8aa8f6b1 | Thomas Thrainer | for instance_name in owned_instances |
254 | 8aa8f6b1 | Thomas Thrainer | for group_uuid in |
255 | 8aa8f6b1 | Thomas Thrainer | self.cfg.GetInstanceNodeGroups(instance_name))
|
256 | 8aa8f6b1 | Thomas Thrainer | |
257 | 8aa8f6b1 | Thomas Thrainer | elif level == locking.LEVEL_NODE:
|
258 | 8aa8f6b1 | Thomas Thrainer | self._LockInstancesNodes()
|
259 | 8aa8f6b1 | Thomas Thrainer | |
260 | 8aa8f6b1 | Thomas Thrainer | elif level == locking.LEVEL_NETWORK:
|
261 | 8aa8f6b1 | Thomas Thrainer | self.needed_locks[locking.LEVEL_NETWORK] = \
|
262 | 8aa8f6b1 | Thomas Thrainer | frozenset(net_uuid
|
263 | 8aa8f6b1 | Thomas Thrainer | for instance_name in owned_instances |
264 | 8aa8f6b1 | Thomas Thrainer | for net_uuid in |
265 | 8aa8f6b1 | Thomas Thrainer | self.cfg.GetInstanceNetworks(instance_name))
|
266 | 8aa8f6b1 | Thomas Thrainer | |
267 | 8aa8f6b1 | Thomas Thrainer | def CheckPrereq(self): |
268 | 8aa8f6b1 | Thomas Thrainer | """Check prerequisites.
|
269 | 8aa8f6b1 | Thomas Thrainer |
|
270 | 8aa8f6b1 | Thomas Thrainer | This only checks the optional instance list against the existing names.
|
271 | 8aa8f6b1 | Thomas Thrainer |
|
272 | 8aa8f6b1 | Thomas Thrainer | """
|
273 | 8aa8f6b1 | Thomas Thrainer | owned_instances = frozenset(self.owned_locks(locking.LEVEL_INSTANCE)) |
274 | 8aa8f6b1 | Thomas Thrainer | owned_groups = frozenset(self.owned_locks(locking.LEVEL_NODEGROUP)) |
275 | 8aa8f6b1 | Thomas Thrainer | owned_nodes = frozenset(self.owned_locks(locking.LEVEL_NODE)) |
276 | 8aa8f6b1 | Thomas Thrainer | owned_networks = frozenset(self.owned_locks(locking.LEVEL_NETWORK)) |
277 | 8aa8f6b1 | Thomas Thrainer | |
278 | 8aa8f6b1 | Thomas Thrainer | if self.wanted_names is None: |
279 | 8aa8f6b1 | Thomas Thrainer | assert self.op.use_locking, "Locking was not used" |
280 | 8aa8f6b1 | Thomas Thrainer | self.wanted_names = owned_instances
|
281 | 8aa8f6b1 | Thomas Thrainer | |
282 | 8aa8f6b1 | Thomas Thrainer | instances = dict(self.cfg.GetMultiInstanceInfo(self.wanted_names)) |
283 | 8aa8f6b1 | Thomas Thrainer | |
284 | 8aa8f6b1 | Thomas Thrainer | if self.op.use_locking: |
285 | 5eacbcae | Thomas Thrainer | CheckInstancesNodeGroups(self.cfg, instances, owned_groups, owned_nodes,
|
286 | 5eacbcae | Thomas Thrainer | None)
|
287 | 8aa8f6b1 | Thomas Thrainer | else:
|
288 | 8aa8f6b1 | Thomas Thrainer | assert not (owned_instances or owned_groups or |
289 | 8aa8f6b1 | Thomas Thrainer | owned_nodes or owned_networks)
|
290 | 8aa8f6b1 | Thomas Thrainer | |
291 | 8aa8f6b1 | Thomas Thrainer | self.wanted_instances = instances.values()
|
292 | 8aa8f6b1 | Thomas Thrainer | |
293 | 8aa8f6b1 | Thomas Thrainer | def _ComputeBlockdevStatus(self, node, instance, dev): |
294 | 8aa8f6b1 | Thomas Thrainer | """Returns the status of a block device
|
295 | 8aa8f6b1 | Thomas Thrainer |
|
296 | 8aa8f6b1 | Thomas Thrainer | """
|
297 | 8aa8f6b1 | Thomas Thrainer | if self.op.static or not node: |
298 | 8aa8f6b1 | Thomas Thrainer | return None |
299 | 8aa8f6b1 | Thomas Thrainer | |
300 | 8aa8f6b1 | Thomas Thrainer | self.cfg.SetDiskID(dev, node)
|
301 | 8aa8f6b1 | Thomas Thrainer | |
302 | 8aa8f6b1 | Thomas Thrainer | result = self.rpc.call_blockdev_find(node, dev)
|
303 | 8aa8f6b1 | Thomas Thrainer | if result.offline:
|
304 | 8aa8f6b1 | Thomas Thrainer | return None |
305 | 8aa8f6b1 | Thomas Thrainer | |
306 | 8aa8f6b1 | Thomas Thrainer | result.Raise("Can't compute disk status for %s" % instance.name)
|
307 | 8aa8f6b1 | Thomas Thrainer | |
308 | 8aa8f6b1 | Thomas Thrainer | status = result.payload |
309 | 8aa8f6b1 | Thomas Thrainer | if status is None: |
310 | 8aa8f6b1 | Thomas Thrainer | return None |
311 | 8aa8f6b1 | Thomas Thrainer | |
312 | 8aa8f6b1 | Thomas Thrainer | return (status.dev_path, status.major, status.minor,
|
313 | 8aa8f6b1 | Thomas Thrainer | status.sync_percent, status.estimated_time, |
314 | 8aa8f6b1 | Thomas Thrainer | status.is_degraded, status.ldisk_status) |
315 | 8aa8f6b1 | Thomas Thrainer | |
316 | 8aa8f6b1 | Thomas Thrainer | def _ComputeDiskStatus(self, instance, snode, dev): |
317 | 8aa8f6b1 | Thomas Thrainer | """Compute block device status.
|
318 | 8aa8f6b1 | Thomas Thrainer |
|
319 | 8aa8f6b1 | Thomas Thrainer | """
|
320 | 5eacbcae | Thomas Thrainer | (anno_dev,) = AnnotateDiskParams(instance, [dev], self.cfg)
|
321 | 8aa8f6b1 | Thomas Thrainer | |
322 | 8aa8f6b1 | Thomas Thrainer | return self._ComputeDiskStatusInner(instance, snode, anno_dev) |
323 | 8aa8f6b1 | Thomas Thrainer | |
324 | 8aa8f6b1 | Thomas Thrainer | def _ComputeDiskStatusInner(self, instance, snode, dev): |
325 | 8aa8f6b1 | Thomas Thrainer | """Compute block device status.
|
326 | 8aa8f6b1 | Thomas Thrainer |
|
327 | 8aa8f6b1 | Thomas Thrainer | @attention: The device has to be annotated already.
|
328 | 8aa8f6b1 | Thomas Thrainer |
|
329 | 8aa8f6b1 | Thomas Thrainer | """
|
330 | 8aa8f6b1 | Thomas Thrainer | if dev.dev_type in constants.LDS_DRBD: |
331 | 8aa8f6b1 | Thomas Thrainer | # we change the snode then (otherwise we use the one passed in)
|
332 | 8aa8f6b1 | Thomas Thrainer | if dev.logical_id[0] == instance.primary_node: |
333 | 8aa8f6b1 | Thomas Thrainer | snode = dev.logical_id[1]
|
334 | 8aa8f6b1 | Thomas Thrainer | else:
|
335 | 8aa8f6b1 | Thomas Thrainer | snode = dev.logical_id[0]
|
336 | 8aa8f6b1 | Thomas Thrainer | |
337 | 8aa8f6b1 | Thomas Thrainer | dev_pstatus = self._ComputeBlockdevStatus(instance.primary_node,
|
338 | 8aa8f6b1 | Thomas Thrainer | instance, dev) |
339 | 8aa8f6b1 | Thomas Thrainer | dev_sstatus = self._ComputeBlockdevStatus(snode, instance, dev)
|
340 | 8aa8f6b1 | Thomas Thrainer | |
341 | 8aa8f6b1 | Thomas Thrainer | if dev.children:
|
342 | 8aa8f6b1 | Thomas Thrainer | dev_children = map(compat.partial(self._ComputeDiskStatusInner, |
343 | 8aa8f6b1 | Thomas Thrainer | instance, snode), |
344 | 8aa8f6b1 | Thomas Thrainer | dev.children) |
345 | 8aa8f6b1 | Thomas Thrainer | else:
|
346 | 8aa8f6b1 | Thomas Thrainer | dev_children = [] |
347 | 8aa8f6b1 | Thomas Thrainer | |
348 | 8aa8f6b1 | Thomas Thrainer | return {
|
349 | 8aa8f6b1 | Thomas Thrainer | "iv_name": dev.iv_name,
|
350 | 8aa8f6b1 | Thomas Thrainer | "dev_type": dev.dev_type,
|
351 | 8aa8f6b1 | Thomas Thrainer | "logical_id": dev.logical_id,
|
352 | 8aa8f6b1 | Thomas Thrainer | "physical_id": dev.physical_id,
|
353 | 8aa8f6b1 | Thomas Thrainer | "pstatus": dev_pstatus,
|
354 | 8aa8f6b1 | Thomas Thrainer | "sstatus": dev_sstatus,
|
355 | 8aa8f6b1 | Thomas Thrainer | "children": dev_children,
|
356 | 8aa8f6b1 | Thomas Thrainer | "mode": dev.mode,
|
357 | 8aa8f6b1 | Thomas Thrainer | "size": dev.size,
|
358 | 8aa8f6b1 | Thomas Thrainer | "name": dev.name,
|
359 | 8aa8f6b1 | Thomas Thrainer | "uuid": dev.uuid,
|
360 | 8aa8f6b1 | Thomas Thrainer | } |
361 | 8aa8f6b1 | Thomas Thrainer | |
362 | 8aa8f6b1 | Thomas Thrainer | def Exec(self, feedback_fn): |
363 | 8aa8f6b1 | Thomas Thrainer | """Gather and return data"""
|
364 | 8aa8f6b1 | Thomas Thrainer | result = {} |
365 | 8aa8f6b1 | Thomas Thrainer | |
366 | 8aa8f6b1 | Thomas Thrainer | cluster = self.cfg.GetClusterInfo()
|
367 | 8aa8f6b1 | Thomas Thrainer | |
368 | 8aa8f6b1 | Thomas Thrainer | node_names = itertools.chain(*(i.all_nodes for i in self.wanted_instances)) |
369 | 8aa8f6b1 | Thomas Thrainer | nodes = dict(self.cfg.GetMultiNodeInfo(node_names)) |
370 | 8aa8f6b1 | Thomas Thrainer | |
371 | 8aa8f6b1 | Thomas Thrainer | groups = dict(self.cfg.GetMultiNodeGroupInfo(node.group |
372 | 8aa8f6b1 | Thomas Thrainer | for node in nodes.values())) |
373 | 8aa8f6b1 | Thomas Thrainer | |
374 | 8aa8f6b1 | Thomas Thrainer | group2name_fn = lambda uuid: groups[uuid].name
|
375 | 8aa8f6b1 | Thomas Thrainer | for instance in self.wanted_instances: |
376 | 8aa8f6b1 | Thomas Thrainer | pnode = nodes[instance.primary_node] |
377 | 8aa8f6b1 | Thomas Thrainer | |
378 | 8aa8f6b1 | Thomas Thrainer | if self.op.static or pnode.offline: |
379 | 8aa8f6b1 | Thomas Thrainer | remote_state = None
|
380 | 8aa8f6b1 | Thomas Thrainer | if pnode.offline:
|
381 | 8aa8f6b1 | Thomas Thrainer | self.LogWarning("Primary node %s is marked offline, returning static" |
382 | 8aa8f6b1 | Thomas Thrainer | " information only for instance %s" %
|
383 | 8aa8f6b1 | Thomas Thrainer | (pnode.name, instance.name)) |
384 | 8aa8f6b1 | Thomas Thrainer | else:
|
385 | 8aa8f6b1 | Thomas Thrainer | remote_info = self.rpc.call_instance_info(instance.primary_node,
|
386 | 8aa8f6b1 | Thomas Thrainer | instance.name, |
387 | 8aa8f6b1 | Thomas Thrainer | instance.hypervisor) |
388 | 8aa8f6b1 | Thomas Thrainer | remote_info.Raise("Error checking node %s" % instance.primary_node)
|
389 | 8aa8f6b1 | Thomas Thrainer | remote_info = remote_info.payload |
390 | 8aa8f6b1 | Thomas Thrainer | if remote_info and "state" in remote_info: |
391 | 8aa8f6b1 | Thomas Thrainer | remote_state = "up"
|
392 | 8aa8f6b1 | Thomas Thrainer | else:
|
393 | 8aa8f6b1 | Thomas Thrainer | if instance.admin_state == constants.ADMINST_UP:
|
394 | 8aa8f6b1 | Thomas Thrainer | remote_state = "down"
|
395 | 8aa8f6b1 | Thomas Thrainer | else:
|
396 | 8aa8f6b1 | Thomas Thrainer | remote_state = instance.admin_state |
397 | 8aa8f6b1 | Thomas Thrainer | |
398 | 8aa8f6b1 | Thomas Thrainer | disks = map(compat.partial(self._ComputeDiskStatus, instance, None), |
399 | 8aa8f6b1 | Thomas Thrainer | instance.disks) |
400 | 8aa8f6b1 | Thomas Thrainer | |
401 | 8aa8f6b1 | Thomas Thrainer | snodes_group_uuids = [nodes[snode_name].group |
402 | 8aa8f6b1 | Thomas Thrainer | for snode_name in instance.secondary_nodes] |
403 | 8aa8f6b1 | Thomas Thrainer | |
404 | 8aa8f6b1 | Thomas Thrainer | result[instance.name] = { |
405 | 8aa8f6b1 | Thomas Thrainer | "name": instance.name,
|
406 | 8aa8f6b1 | Thomas Thrainer | "config_state": instance.admin_state,
|
407 | 8aa8f6b1 | Thomas Thrainer | "run_state": remote_state,
|
408 | 8aa8f6b1 | Thomas Thrainer | "pnode": instance.primary_node,
|
409 | 8aa8f6b1 | Thomas Thrainer | "pnode_group_uuid": pnode.group,
|
410 | 8aa8f6b1 | Thomas Thrainer | "pnode_group_name": group2name_fn(pnode.group),
|
411 | 8aa8f6b1 | Thomas Thrainer | "snodes": instance.secondary_nodes,
|
412 | 8aa8f6b1 | Thomas Thrainer | "snodes_group_uuids": snodes_group_uuids,
|
413 | 8aa8f6b1 | Thomas Thrainer | "snodes_group_names": map(group2name_fn, snodes_group_uuids), |
414 | 8aa8f6b1 | Thomas Thrainer | "os": instance.os,
|
415 | 8aa8f6b1 | Thomas Thrainer | # this happens to be the same format used for hooks
|
416 | 5eacbcae | Thomas Thrainer | "nics": NICListToTuple(self, instance.nics), |
417 | 8aa8f6b1 | Thomas Thrainer | "disk_template": instance.disk_template,
|
418 | 8aa8f6b1 | Thomas Thrainer | "disks": disks,
|
419 | 8aa8f6b1 | Thomas Thrainer | "hypervisor": instance.hypervisor,
|
420 | 8aa8f6b1 | Thomas Thrainer | "network_port": instance.network_port,
|
421 | 8aa8f6b1 | Thomas Thrainer | "hv_instance": instance.hvparams,
|
422 | 8aa8f6b1 | Thomas Thrainer | "hv_actual": cluster.FillHV(instance, skip_globals=True), |
423 | 8aa8f6b1 | Thomas Thrainer | "be_instance": instance.beparams,
|
424 | 8aa8f6b1 | Thomas Thrainer | "be_actual": cluster.FillBE(instance),
|
425 | 8aa8f6b1 | Thomas Thrainer | "os_instance": instance.osparams,
|
426 | 8aa8f6b1 | Thomas Thrainer | "os_actual": cluster.SimpleFillOS(instance.os, instance.osparams),
|
427 | 8aa8f6b1 | Thomas Thrainer | "serial_no": instance.serial_no,
|
428 | 8aa8f6b1 | Thomas Thrainer | "mtime": instance.mtime,
|
429 | 8aa8f6b1 | Thomas Thrainer | "ctime": instance.ctime,
|
430 | 8aa8f6b1 | Thomas Thrainer | "uuid": instance.uuid,
|
431 | 8aa8f6b1 | Thomas Thrainer | } |
432 | 8aa8f6b1 | Thomas Thrainer | |
433 | 8aa8f6b1 | Thomas Thrainer | return result |