Statistics
| Branch: | Tag: | Revision:

root / lib / cmdlib / operating_system.py @ b3fc101f

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 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 7f37f0ca Dimitris Bliablias
                          blacklisted=(os_name in cluster.blacklisted_os),
108 7f37f0ca Dimitris Bliablias
                          os_hvp={}, osparams={})
109 1be6b00e Thomas Thrainer
110 1be6b00e Thomas Thrainer
      variants = set()
111 1be6b00e Thomas Thrainer
      parameters = set()
112 1be6b00e Thomas Thrainer
      api_versions = set()
113 1be6b00e Thomas Thrainer
114 1be6b00e Thomas Thrainer
      for idx, osl in enumerate(os_data.values()):
115 1be6b00e Thomas Thrainer
        info.valid = bool(info.valid and osl and osl[0][1])
116 1be6b00e Thomas Thrainer
        if not info.valid:
117 1be6b00e Thomas Thrainer
          break
118 1be6b00e Thomas Thrainer
119 1be6b00e Thomas Thrainer
        (node_variants, node_params, node_api) = osl[0][3:6]
120 1be6b00e Thomas Thrainer
        if idx == 0:
121 1be6b00e Thomas Thrainer
          # First entry
122 1be6b00e Thomas Thrainer
          variants.update(node_variants)
123 1be6b00e Thomas Thrainer
          parameters.update(node_params)
124 1be6b00e Thomas Thrainer
          api_versions.update(node_api)
125 1be6b00e Thomas Thrainer
        else:
126 1be6b00e Thomas Thrainer
          # Filter out inconsistent values
127 1be6b00e Thomas Thrainer
          variants.intersection_update(node_variants)
128 1be6b00e Thomas Thrainer
          parameters.intersection_update(node_params)
129 1be6b00e Thomas Thrainer
          api_versions.intersection_update(node_api)
130 1be6b00e Thomas Thrainer
131 1be6b00e Thomas Thrainer
      info.variants = list(variants)
132 1be6b00e Thomas Thrainer
      info.parameters = list(parameters)
133 1be6b00e Thomas Thrainer
      info.api_versions = list(api_versions)
134 1be6b00e Thomas Thrainer
135 7f37f0ca Dimitris Bliablias
      for variant in variants:
136 7f37f0ca Dimitris Bliablias
        name = "+".join([os_name, variant])
137 7f37f0ca Dimitris Bliablias
        if name in cluster.os_hvp.keys():
138 7f37f0ca Dimitris Bliablias
          info.os_hvp[name] = cluster.os_hvp.get(name)
139 7f37f0ca Dimitris Bliablias
        if name in cluster.osparams.keys():
140 7f37f0ca Dimitris Bliablias
          info.osparams[name] = cluster.osparams.get(name)
141 7f37f0ca Dimitris Bliablias
142 1be6b00e Thomas Thrainer
      data[os_name] = info
143 1be6b00e Thomas Thrainer
144 1be6b00e Thomas Thrainer
    # Prepare data in requested order
145 1be6b00e Thomas Thrainer
    return [data[name] for name in self._GetNames(lu, pol.keys(), None)
146 1be6b00e Thomas Thrainer
            if name in data]
147 1be6b00e Thomas Thrainer
148 1be6b00e Thomas Thrainer
149 1be6b00e Thomas Thrainer
class LUOsDiagnose(NoHooksLU):
150 1be6b00e Thomas Thrainer
  """Logical unit for OS diagnose/query.
151 1be6b00e Thomas Thrainer

152 1be6b00e Thomas Thrainer
  """
153 1be6b00e Thomas Thrainer
  REQ_BGL = False
154 1be6b00e Thomas Thrainer
155 1be6b00e Thomas Thrainer
  @staticmethod
156 1be6b00e Thomas Thrainer
  def _BuildFilter(fields, names):
157 1be6b00e Thomas Thrainer
    """Builds a filter for querying OSes.
158 1be6b00e Thomas Thrainer

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