Statistics
| Branch: | Tag: | Revision:

root / lib / cmdlib / operating_system.py @ 44ffd981

History | View | Annotate | Download (6.2 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 1c3231aa Thomas Thrainer
        map, with node UUIDs as keys and tuples of (path, status, diagnose,
62 1be6b00e Thomas Thrainer
        variants, parameters, api_versions) as values, eg::
63 1be6b00e Thomas Thrainer

64 1c3231aa Thomas Thrainer
          {"debian-etch": {"node1-uuid": [(/usr/lib/..., True, "", [], []),
65 1c3231aa Thomas Thrainer
                                          (/srv/..., False, "invalid api")],
66 1c3231aa Thomas Thrainer
                           "node2-uuid": [(/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 1c3231aa Thomas Thrainer
    good_node_uuids = [node_uuid for node_uuid in rlist
75 1c3231aa Thomas Thrainer
                       if not rlist[node_uuid].fail_msg]
76 1c3231aa Thomas Thrainer
    for node_uuid, 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 1c3231aa Thomas Thrainer
          for nuuid in good_node_uuids:
86 1c3231aa Thomas Thrainer
            all_os[name][nuuid] = []
87 1be6b00e Thomas Thrainer
        # convert params from [name, help] to (name, help)
88 1be6b00e Thomas Thrainer
        params = [tuple(v) for v in params]
89 1c3231aa Thomas Thrainer
        all_os[name][node_uuid].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 1c3231aa Thomas Thrainer
    valid_node_uuids = [node.uuid
104 1c3231aa Thomas Thrainer
                        for node in lu.cfg.GetAllNodesInfo().values()
105 1c3231aa Thomas Thrainer
                        if not node.offline and node.vm_capable]
106 1c3231aa Thomas Thrainer
    pol = self._DiagnoseByOS(lu.rpc.call_os_diagnose(valid_node_uuids))
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)