root / lib / cmdlib / operating_system.py @ b54ecf12
History | View | Annotate | Download (6.1 kB)
1 | 1be6b00e | Thomas Thrainer | #
|
---|---|---|---|
2 | 1be6b00e | Thomas Thrainer | #
|
3 | 1be6b00e | Thomas Thrainer | |
4 | 1be6b00e | Thomas Thrainer | # Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Google Inc.
|
5 | 1be6b00e | Thomas Thrainer | #
|
6 | 1be6b00e | Thomas Thrainer | # This program is free software; you can redistribute it and/or modify
|
7 | 1be6b00e | Thomas Thrainer | # it under the terms of the GNU General Public License as published by
|
8 | 1be6b00e | Thomas Thrainer | # the Free Software Foundation; either version 2 of the License, or
|
9 | 1be6b00e | Thomas Thrainer | # (at your option) any later version.
|
10 | 1be6b00e | Thomas Thrainer | #
|
11 | 1be6b00e | Thomas Thrainer | # This program is distributed in the hope that it will be useful, but
|
12 | 1be6b00e | Thomas Thrainer | # WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 | 1be6b00e | Thomas Thrainer | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14 | 1be6b00e | Thomas Thrainer | # General Public License for more details.
|
15 | 1be6b00e | Thomas Thrainer | #
|
16 | 1be6b00e | Thomas Thrainer | # You should have received a copy of the GNU General Public License
|
17 | 1be6b00e | Thomas Thrainer | # along with this program; if not, write to the Free Software
|
18 | 1be6b00e | Thomas Thrainer | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
19 | 1be6b00e | Thomas Thrainer | # 02110-1301, USA.
|
20 | 1be6b00e | Thomas Thrainer | |
21 | 1be6b00e | Thomas Thrainer | |
22 | 1be6b00e | Thomas Thrainer | """Logical units dealing with OS."""
|
23 | 1be6b00e | Thomas Thrainer | |
24 | 1be6b00e | Thomas Thrainer | from ganeti import compat |
25 | 1be6b00e | Thomas Thrainer | from ganeti import locking |
26 | 1be6b00e | Thomas Thrainer | from ganeti import qlang |
27 | 1be6b00e | Thomas Thrainer | from ganeti import query |
28 | 5eacbcae | Thomas Thrainer | from ganeti.cmdlib.base import QueryBase, NoHooksLU |
29 | 1be6b00e | Thomas Thrainer | |
30 | 1be6b00e | Thomas Thrainer | |
31 | 5eacbcae | Thomas Thrainer | class OsQuery(QueryBase): |
32 | 1be6b00e | Thomas Thrainer | FIELDS = query.OS_FIELDS |
33 | 1be6b00e | Thomas Thrainer | |
34 | 1be6b00e | Thomas Thrainer | def ExpandNames(self, lu): |
35 | 1be6b00e | Thomas Thrainer | # Lock all nodes in shared mode
|
36 | 1be6b00e | Thomas Thrainer | # Temporary removal of locks, should be reverted later
|
37 | 1be6b00e | Thomas Thrainer | # TODO: reintroduce locks when they are lighter-weight
|
38 | 1be6b00e | Thomas Thrainer | lu.needed_locks = {} |
39 | 1be6b00e | Thomas Thrainer | #self.share_locks[locking.LEVEL_NODE] = 1
|
40 | 1be6b00e | Thomas Thrainer | #self.needed_locks[locking.LEVEL_NODE] = locking.ALL_SET
|
41 | 1be6b00e | Thomas Thrainer | |
42 | 1be6b00e | Thomas Thrainer | # The following variables interact with _QueryBase._GetNames
|
43 | 1be6b00e | Thomas Thrainer | if self.names: |
44 | 1be6b00e | Thomas Thrainer | self.wanted = self.names |
45 | 1be6b00e | Thomas Thrainer | else:
|
46 | 1be6b00e | Thomas Thrainer | self.wanted = locking.ALL_SET
|
47 | 1be6b00e | Thomas Thrainer | |
48 | 1be6b00e | Thomas Thrainer | self.do_locking = self.use_locking |
49 | 1be6b00e | Thomas Thrainer | |
50 | 1be6b00e | Thomas Thrainer | def DeclareLocks(self, lu, level): |
51 | 1be6b00e | Thomas Thrainer | pass
|
52 | 1be6b00e | Thomas Thrainer | |
53 | 1be6b00e | Thomas Thrainer | @staticmethod
|
54 | 1be6b00e | Thomas Thrainer | def _DiagnoseByOS(rlist): |
55 | 1be6b00e | Thomas Thrainer | """Remaps a per-node return list into an a per-os per-node dictionary
|
56 | 1be6b00e | Thomas Thrainer |
|
57 | 1be6b00e | Thomas Thrainer | @param rlist: a map with node names as keys and OS objects as values
|
58 | 1be6b00e | Thomas Thrainer |
|
59 | 1be6b00e | Thomas Thrainer | @rtype: dict
|
60 | 1be6b00e | Thomas Thrainer | @return: a dictionary with osnames as keys and as value another
|
61 | 1be6b00e | Thomas Thrainer | map, with nodes as keys and tuples of (path, status, diagnose,
|
62 | 1be6b00e | Thomas Thrainer | variants, parameters, api_versions) as values, eg::
|
63 | 1be6b00e | Thomas Thrainer |
|
64 | 1be6b00e | Thomas Thrainer | {"debian-etch": {"node1": [(/usr/lib/..., True, "", [], []),
|
65 | 1be6b00e | Thomas Thrainer | (/srv/..., False, "invalid api")],
|
66 | 1be6b00e | Thomas Thrainer | "node2": [(/srv/..., True, "", [], [])]}
|
67 | 1be6b00e | Thomas Thrainer | }
|
68 | 1be6b00e | Thomas Thrainer |
|
69 | 1be6b00e | Thomas Thrainer | """
|
70 | 1be6b00e | Thomas Thrainer | all_os = {} |
71 | 1be6b00e | Thomas Thrainer | # we build here the list of nodes that didn't fail the RPC (at RPC
|
72 | 1be6b00e | Thomas Thrainer | # level), so that nodes with a non-responding node daemon don't
|
73 | 1be6b00e | Thomas Thrainer | # make all OSes invalid
|
74 | 1be6b00e | Thomas Thrainer | good_nodes = [node_name for node_name in rlist |
75 | 1be6b00e | Thomas Thrainer | if not rlist[node_name].fail_msg] |
76 | 1be6b00e | Thomas Thrainer | for node_name, nr in rlist.items(): |
77 | 1be6b00e | Thomas Thrainer | if nr.fail_msg or not nr.payload: |
78 | 1be6b00e | Thomas Thrainer | continue
|
79 | 1be6b00e | Thomas Thrainer | for (name, path, status, diagnose, variants,
|
80 | 1be6b00e | Thomas Thrainer | params, api_versions) in nr.payload:
|
81 | 1be6b00e | Thomas Thrainer | if name not in all_os: |
82 | 1be6b00e | Thomas Thrainer | # build a list of nodes for this os containing empty lists
|
83 | 1be6b00e | Thomas Thrainer | # for each node in node_list
|
84 | 1be6b00e | Thomas Thrainer | all_os[name] = {} |
85 | 1be6b00e | Thomas Thrainer | for nname in good_nodes: |
86 | 1be6b00e | Thomas Thrainer | all_os[name][nname] = [] |
87 | 1be6b00e | Thomas Thrainer | # convert params from [name, help] to (name, help)
|
88 | 1be6b00e | Thomas Thrainer | params = [tuple(v) for v in params] |
89 | 1be6b00e | Thomas Thrainer | all_os[name][node_name].append((path, status, diagnose, |
90 | 1be6b00e | Thomas Thrainer | variants, params, api_versions)) |
91 | 1be6b00e | Thomas Thrainer | return all_os
|
92 | 1be6b00e | Thomas Thrainer | |
93 | 1be6b00e | Thomas Thrainer | def _GetQueryData(self, lu): |
94 | 1be6b00e | Thomas Thrainer | """Computes the list of nodes and their attributes.
|
95 | 1be6b00e | Thomas Thrainer |
|
96 | 1be6b00e | Thomas Thrainer | """
|
97 | 1be6b00e | Thomas Thrainer | # Locking is not used
|
98 | 1be6b00e | Thomas Thrainer | assert not (compat.any(lu.glm.is_owned(level) |
99 | 1be6b00e | Thomas Thrainer | for level in locking.LEVELS |
100 | 1be6b00e | Thomas Thrainer | if level != locking.LEVEL_CLUSTER) or |
101 | 1be6b00e | Thomas Thrainer | self.do_locking or self.use_locking) |
102 | 1be6b00e | Thomas Thrainer | |
103 | 1be6b00e | Thomas Thrainer | valid_nodes = [node.name |
104 | 1be6b00e | Thomas Thrainer | for node in lu.cfg.GetAllNodesInfo().values() |
105 | 1be6b00e | Thomas Thrainer | if not node.offline and node.vm_capable] |
106 | 1be6b00e | Thomas Thrainer | pol = self._DiagnoseByOS(lu.rpc.call_os_diagnose(valid_nodes))
|
107 | 1be6b00e | Thomas Thrainer | cluster = lu.cfg.GetClusterInfo() |
108 | 1be6b00e | Thomas Thrainer | |
109 | 1be6b00e | Thomas Thrainer | data = {} |
110 | 1be6b00e | Thomas Thrainer | |
111 | 1be6b00e | Thomas Thrainer | for (os_name, os_data) in pol.items(): |
112 | 1be6b00e | Thomas Thrainer | info = query.OsInfo(name=os_name, valid=True, node_status=os_data,
|
113 | 1be6b00e | Thomas Thrainer | hidden=(os_name in cluster.hidden_os),
|
114 | 1be6b00e | Thomas Thrainer | blacklisted=(os_name in cluster.blacklisted_os))
|
115 | 1be6b00e | Thomas Thrainer | |
116 | 1be6b00e | Thomas Thrainer | variants = set()
|
117 | 1be6b00e | Thomas Thrainer | parameters = set()
|
118 | 1be6b00e | Thomas Thrainer | api_versions = set()
|
119 | 1be6b00e | Thomas Thrainer | |
120 | 1be6b00e | Thomas Thrainer | for idx, osl in enumerate(os_data.values()): |
121 | 1be6b00e | Thomas Thrainer | info.valid = bool(info.valid and osl and osl[0][1]) |
122 | 1be6b00e | Thomas Thrainer | if not info.valid: |
123 | 1be6b00e | Thomas Thrainer | break
|
124 | 1be6b00e | Thomas Thrainer | |
125 | 1be6b00e | Thomas Thrainer | (node_variants, node_params, node_api) = osl[0][3:6] |
126 | 1be6b00e | Thomas Thrainer | if idx == 0: |
127 | 1be6b00e | Thomas Thrainer | # First entry
|
128 | 1be6b00e | Thomas Thrainer | variants.update(node_variants) |
129 | 1be6b00e | Thomas Thrainer | parameters.update(node_params) |
130 | 1be6b00e | Thomas Thrainer | api_versions.update(node_api) |
131 | 1be6b00e | Thomas Thrainer | else:
|
132 | 1be6b00e | Thomas Thrainer | # Filter out inconsistent values
|
133 | 1be6b00e | Thomas Thrainer | variants.intersection_update(node_variants) |
134 | 1be6b00e | Thomas Thrainer | parameters.intersection_update(node_params) |
135 | 1be6b00e | Thomas Thrainer | api_versions.intersection_update(node_api) |
136 | 1be6b00e | Thomas Thrainer | |
137 | 1be6b00e | Thomas Thrainer | info.variants = list(variants)
|
138 | 1be6b00e | Thomas Thrainer | info.parameters = list(parameters)
|
139 | 1be6b00e | Thomas Thrainer | info.api_versions = list(api_versions)
|
140 | 1be6b00e | Thomas Thrainer | |
141 | 1be6b00e | Thomas Thrainer | data[os_name] = info |
142 | 1be6b00e | Thomas Thrainer | |
143 | 1be6b00e | Thomas Thrainer | # Prepare data in requested order
|
144 | 1be6b00e | Thomas Thrainer | return [data[name] for name in self._GetNames(lu, pol.keys(), None) |
145 | 1be6b00e | Thomas Thrainer | if name in data] |
146 | 1be6b00e | Thomas Thrainer | |
147 | 1be6b00e | Thomas Thrainer | |
148 | 1be6b00e | Thomas Thrainer | class LUOsDiagnose(NoHooksLU): |
149 | 1be6b00e | Thomas Thrainer | """Logical unit for OS diagnose/query.
|
150 | 1be6b00e | Thomas Thrainer |
|
151 | 1be6b00e | Thomas Thrainer | """
|
152 | 1be6b00e | Thomas Thrainer | REQ_BGL = False
|
153 | 1be6b00e | Thomas Thrainer | |
154 | 1be6b00e | Thomas Thrainer | @staticmethod
|
155 | 1be6b00e | Thomas Thrainer | def _BuildFilter(fields, names): |
156 | 1be6b00e | Thomas Thrainer | """Builds a filter for querying OSes.
|
157 | 1be6b00e | Thomas Thrainer |
|
158 | 1be6b00e | Thomas Thrainer | """
|
159 | 1be6b00e | Thomas Thrainer | name_filter = qlang.MakeSimpleFilter("name", names)
|
160 | 1be6b00e | Thomas Thrainer | |
161 | 1be6b00e | Thomas Thrainer | # Legacy behaviour: Hide hidden, blacklisted or invalid OSes if the
|
162 | 1be6b00e | Thomas Thrainer | # respective field is not requested
|
163 | 1be6b00e | Thomas Thrainer | status_filter = [[qlang.OP_NOT, [qlang.OP_TRUE, fname]] |
164 | 1be6b00e | Thomas Thrainer | for fname in ["hidden", "blacklisted"] |
165 | 1be6b00e | Thomas Thrainer | if fname not in fields] |
166 | 1be6b00e | Thomas Thrainer | if "valid" not in fields: |
167 | 1be6b00e | Thomas Thrainer | status_filter.append([qlang.OP_TRUE, "valid"])
|
168 | 1be6b00e | Thomas Thrainer | |
169 | 1be6b00e | Thomas Thrainer | if status_filter:
|
170 | 1be6b00e | Thomas Thrainer | status_filter.insert(0, qlang.OP_AND)
|
171 | 1be6b00e | Thomas Thrainer | else:
|
172 | 1be6b00e | Thomas Thrainer | status_filter = None
|
173 | 1be6b00e | Thomas Thrainer | |
174 | 1be6b00e | Thomas Thrainer | if name_filter and status_filter: |
175 | 1be6b00e | Thomas Thrainer | return [qlang.OP_AND, name_filter, status_filter]
|
176 | 1be6b00e | Thomas Thrainer | elif name_filter:
|
177 | 1be6b00e | Thomas Thrainer | return name_filter
|
178 | 1be6b00e | Thomas Thrainer | else:
|
179 | 1be6b00e | Thomas Thrainer | return status_filter
|
180 | 1be6b00e | Thomas Thrainer | |
181 | 1be6b00e | Thomas Thrainer | def CheckArguments(self): |
182 | 5eacbcae | Thomas Thrainer | self.oq = OsQuery(self._BuildFilter(self.op.output_fields, self.op.names), |
183 | 1be6b00e | Thomas Thrainer | self.op.output_fields, False) |
184 | 1be6b00e | Thomas Thrainer | |
185 | 1be6b00e | Thomas Thrainer | def ExpandNames(self): |
186 | 1be6b00e | Thomas Thrainer | self.oq.ExpandNames(self) |
187 | 1be6b00e | Thomas Thrainer | |
188 | 1be6b00e | Thomas Thrainer | def Exec(self, feedback_fn): |
189 | 1be6b00e | Thomas Thrainer | return self.oq.OldStyleQuery(self) |