Statistics
| Branch: | Tag: | Revision:

root / lib / cmdlib / operating_system.py @ 87ed6b79

History | View | Annotate | Download (5.9 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 locking
25 1be6b00e Thomas Thrainer
from ganeti import qlang
26 1be6b00e Thomas Thrainer
from ganeti import query
27 5eacbcae Thomas Thrainer
from ganeti.cmdlib.base import QueryBase, NoHooksLU
28 1be6b00e Thomas Thrainer
29 1be6b00e Thomas Thrainer
30 5eacbcae Thomas Thrainer
class OsQuery(QueryBase):
31 1be6b00e Thomas Thrainer
  FIELDS = query.OS_FIELDS
32 1be6b00e Thomas Thrainer
33 1be6b00e Thomas Thrainer
  def ExpandNames(self, lu):
34 1be6b00e Thomas Thrainer
    # Lock all nodes in shared mode
35 1be6b00e Thomas Thrainer
    # Temporary removal of locks, should be reverted later
36 1be6b00e Thomas Thrainer
    # TODO: reintroduce locks when they are lighter-weight
37 1be6b00e Thomas Thrainer
    lu.needed_locks = {}
38 1be6b00e Thomas Thrainer
    #self.share_locks[locking.LEVEL_NODE] = 1
39 1be6b00e Thomas Thrainer
    #self.needed_locks[locking.LEVEL_NODE] = locking.ALL_SET
40 1be6b00e Thomas Thrainer
41 1be6b00e Thomas Thrainer
    # The following variables interact with _QueryBase._GetNames
42 1be6b00e Thomas Thrainer
    if self.names:
43 1be6b00e Thomas Thrainer
      self.wanted = self.names
44 1be6b00e Thomas Thrainer
    else:
45 1be6b00e Thomas Thrainer
      self.wanted = locking.ALL_SET
46 1be6b00e Thomas Thrainer
47 1be6b00e Thomas Thrainer
    self.do_locking = self.use_locking
48 1be6b00e Thomas Thrainer
49 1be6b00e Thomas Thrainer
  def DeclareLocks(self, lu, level):
50 1be6b00e Thomas Thrainer
    pass
51 1be6b00e Thomas Thrainer
52 1be6b00e Thomas Thrainer
  @staticmethod
53 1be6b00e Thomas Thrainer
  def _DiagnoseByOS(rlist):
54 1be6b00e Thomas Thrainer
    """Remaps a per-node return list into an a per-os per-node dictionary
55 1be6b00e Thomas Thrainer

56 1be6b00e Thomas Thrainer
    @param rlist: a map with node names as keys and OS objects as values
57 1be6b00e Thomas Thrainer

58 1be6b00e Thomas Thrainer
    @rtype: dict
59 1be6b00e Thomas Thrainer
    @return: a dictionary with osnames as keys and as value another
60 1c3231aa Thomas Thrainer
        map, with node UUIDs as keys and tuples of (path, status, diagnose,
61 1be6b00e Thomas Thrainer
        variants, parameters, api_versions) as values, eg::
62 1be6b00e Thomas Thrainer

63 1c3231aa Thomas Thrainer
          {"debian-etch": {"node1-uuid": [(/usr/lib/..., True, "", [], []),
64 1c3231aa Thomas Thrainer
                                          (/srv/..., False, "invalid api")],
65 1c3231aa Thomas Thrainer
                           "node2-uuid": [(/srv/..., True, "", [], [])]}
66 1be6b00e Thomas Thrainer
          }
67 1be6b00e Thomas Thrainer

68 1be6b00e Thomas Thrainer
    """
69 1be6b00e Thomas Thrainer
    all_os = {}
70 1be6b00e Thomas Thrainer
    # we build here the list of nodes that didn't fail the RPC (at RPC
71 1be6b00e Thomas Thrainer
    # level), so that nodes with a non-responding node daemon don't
72 1be6b00e Thomas Thrainer
    # make all OSes invalid
73 1c3231aa Thomas Thrainer
    good_node_uuids = [node_uuid for node_uuid in rlist
74 1c3231aa Thomas Thrainer
                       if not rlist[node_uuid].fail_msg]
75 1c3231aa Thomas Thrainer
    for node_uuid, nr in rlist.items():
76 1be6b00e Thomas Thrainer
      if nr.fail_msg or not nr.payload:
77 1be6b00e Thomas Thrainer
        continue
78 1be6b00e Thomas Thrainer
      for (name, path, status, diagnose, variants,
79 1be6b00e Thomas Thrainer
           params, api_versions) in nr.payload:
80 1be6b00e Thomas Thrainer
        if name not in all_os:
81 1be6b00e Thomas Thrainer
          # build a list of nodes for this os containing empty lists
82 1be6b00e Thomas Thrainer
          # for each node in node_list
83 1be6b00e Thomas Thrainer
          all_os[name] = {}
84 1c3231aa Thomas Thrainer
          for nuuid in good_node_uuids:
85 1c3231aa Thomas Thrainer
            all_os[name][nuuid] = []
86 1be6b00e Thomas Thrainer
        # convert params from [name, help] to (name, help)
87 1be6b00e Thomas Thrainer
        params = [tuple(v) for v in params]
88 1c3231aa Thomas Thrainer
        all_os[name][node_uuid].append((path, status, diagnose,
89 1be6b00e Thomas Thrainer
                                        variants, params, api_versions))
90 1be6b00e Thomas Thrainer
    return all_os
91 1be6b00e Thomas Thrainer
92 1be6b00e Thomas Thrainer
  def _GetQueryData(self, lu):
93 1be6b00e Thomas Thrainer
    """Computes the list of nodes and their attributes.
94 1be6b00e Thomas Thrainer

95 1be6b00e Thomas Thrainer
    """
96 1c3231aa Thomas Thrainer
    valid_node_uuids = [node.uuid
97 1c3231aa Thomas Thrainer
                        for node in lu.cfg.GetAllNodesInfo().values()
98 1c3231aa Thomas Thrainer
                        if not node.offline and node.vm_capable]
99 1c3231aa Thomas Thrainer
    pol = self._DiagnoseByOS(lu.rpc.call_os_diagnose(valid_node_uuids))
100 1be6b00e Thomas Thrainer
    cluster = lu.cfg.GetClusterInfo()
101 1be6b00e Thomas Thrainer
102 1be6b00e Thomas Thrainer
    data = {}
103 1be6b00e Thomas Thrainer
104 1be6b00e Thomas Thrainer
    for (os_name, os_data) in pol.items():
105 1be6b00e Thomas Thrainer
      info = query.OsInfo(name=os_name, valid=True, node_status=os_data,
106 1be6b00e Thomas Thrainer
                          hidden=(os_name in cluster.hidden_os),
107 1be6b00e Thomas Thrainer
                          blacklisted=(os_name in cluster.blacklisted_os))
108 1be6b00e Thomas Thrainer
109 1be6b00e Thomas Thrainer
      variants = set()
110 1be6b00e Thomas Thrainer
      parameters = set()
111 1be6b00e Thomas Thrainer
      api_versions = set()
112 1be6b00e Thomas Thrainer
113 1be6b00e Thomas Thrainer
      for idx, osl in enumerate(os_data.values()):
114 1be6b00e Thomas Thrainer
        info.valid = bool(info.valid and osl and osl[0][1])
115 1be6b00e Thomas Thrainer
        if not info.valid:
116 1be6b00e Thomas Thrainer
          break
117 1be6b00e Thomas Thrainer
118 1be6b00e Thomas Thrainer
        (node_variants, node_params, node_api) = osl[0][3:6]
119 1be6b00e Thomas Thrainer
        if idx == 0:
120 1be6b00e Thomas Thrainer
          # First entry
121 1be6b00e Thomas Thrainer
          variants.update(node_variants)
122 1be6b00e Thomas Thrainer
          parameters.update(node_params)
123 1be6b00e Thomas Thrainer
          api_versions.update(node_api)
124 1be6b00e Thomas Thrainer
        else:
125 1be6b00e Thomas Thrainer
          # Filter out inconsistent values
126 1be6b00e Thomas Thrainer
          variants.intersection_update(node_variants)
127 1be6b00e Thomas Thrainer
          parameters.intersection_update(node_params)
128 1be6b00e Thomas Thrainer
          api_versions.intersection_update(node_api)
129 1be6b00e Thomas Thrainer
130 1be6b00e Thomas Thrainer
      info.variants = list(variants)
131 1be6b00e Thomas Thrainer
      info.parameters = list(parameters)
132 1be6b00e Thomas Thrainer
      info.api_versions = list(api_versions)
133 1be6b00e Thomas Thrainer
134 1be6b00e Thomas Thrainer
      data[os_name] = info
135 1be6b00e Thomas Thrainer
136 1be6b00e Thomas Thrainer
    # Prepare data in requested order
137 1be6b00e Thomas Thrainer
    return [data[name] for name in self._GetNames(lu, pol.keys(), None)
138 1be6b00e Thomas Thrainer
            if name in data]
139 1be6b00e Thomas Thrainer
140 1be6b00e Thomas Thrainer
141 1be6b00e Thomas Thrainer
class LUOsDiagnose(NoHooksLU):
142 1be6b00e Thomas Thrainer
  """Logical unit for OS diagnose/query.
143 1be6b00e Thomas Thrainer

144 1be6b00e Thomas Thrainer
  """
145 1be6b00e Thomas Thrainer
  REQ_BGL = False
146 1be6b00e Thomas Thrainer
147 1be6b00e Thomas Thrainer
  @staticmethod
148 1be6b00e Thomas Thrainer
  def _BuildFilter(fields, names):
149 1be6b00e Thomas Thrainer
    """Builds a filter for querying OSes.
150 1be6b00e Thomas Thrainer

151 1be6b00e Thomas Thrainer
    """
152 1be6b00e Thomas Thrainer
    name_filter = qlang.MakeSimpleFilter("name", names)
153 1be6b00e Thomas Thrainer
154 1be6b00e Thomas Thrainer
    # Legacy behaviour: Hide hidden, blacklisted or invalid OSes if the
155 1be6b00e Thomas Thrainer
    # respective field is not requested
156 1be6b00e Thomas Thrainer
    status_filter = [[qlang.OP_NOT, [qlang.OP_TRUE, fname]]
157 1be6b00e Thomas Thrainer
                     for fname in ["hidden", "blacklisted"]
158 1be6b00e Thomas Thrainer
                     if fname not in fields]
159 1be6b00e Thomas Thrainer
    if "valid" not in fields:
160 1be6b00e Thomas Thrainer
      status_filter.append([qlang.OP_TRUE, "valid"])
161 1be6b00e Thomas Thrainer
162 1be6b00e Thomas Thrainer
    if status_filter:
163 1be6b00e Thomas Thrainer
      status_filter.insert(0, qlang.OP_AND)
164 1be6b00e Thomas Thrainer
    else:
165 1be6b00e Thomas Thrainer
      status_filter = None
166 1be6b00e Thomas Thrainer
167 1be6b00e Thomas Thrainer
    if name_filter and status_filter:
168 1be6b00e Thomas Thrainer
      return [qlang.OP_AND, name_filter, status_filter]
169 1be6b00e Thomas Thrainer
    elif name_filter:
170 1be6b00e Thomas Thrainer
      return name_filter
171 1be6b00e Thomas Thrainer
    else:
172 1be6b00e Thomas Thrainer
      return status_filter
173 1be6b00e Thomas Thrainer
174 1be6b00e Thomas Thrainer
  def CheckArguments(self):
175 5eacbcae Thomas Thrainer
    self.oq = OsQuery(self._BuildFilter(self.op.output_fields, self.op.names),
176 1be6b00e Thomas Thrainer
                       self.op.output_fields, False)
177 1be6b00e Thomas Thrainer
178 1be6b00e Thomas Thrainer
  def ExpandNames(self):
179 1be6b00e Thomas Thrainer
    self.oq.ExpandNames(self)
180 1be6b00e Thomas Thrainer
181 1be6b00e Thomas Thrainer
  def Exec(self, feedback_fn):
182 1be6b00e Thomas Thrainer
    return self.oq.OldStyleQuery(self)