Commit 1be6b00e authored by Thomas Thrainer's avatar Thomas Thrainer

Extract os related logical units from cmdlib

All LUOs* classes are extracted to operating_system.py.
Signed-off-by: default avatarThomas Thrainer <thomasth@google.com>
Reviewed-by: default avatarBernardo Dal Seno <bdalseno@google.com>
parent ec3cc4a8
......@@ -318,6 +318,7 @@ cmdlib_PYTHON = \
lib/cmdlib/instance_utils.py \
lib/cmdlib/backup.py \
lib/cmdlib/query.py \
lib/cmdlib/operating_system.py \
lib/cmdlib/tags.py \
lib/cmdlib/network.py \
lib/cmdlib/test.py
......
......@@ -82,6 +82,7 @@ from ganeti.cmdlib.instance import LUInstanceCreate, LUInstanceRename, \
from ganeti.cmdlib.backup import LUBackupQuery, LUBackupPrepare, \
LUBackupExport, LUBackupRemove
from ganeti.cmdlib.query import LUQuery, LUQueryFields
from ganeti.cmdlib.operating_system import LUOsDiagnose
from ganeti.cmdlib.tags import LUTagsGet, LUTagsSearch, LUTagsSet, LUTagsDel
from ganeti.cmdlib.network import LUNetworkAdd, LUNetworkRemove, \
LUNetworkSetParams, LUNetworkQuery, LUNetworkConnect, LUNetworkDisconnect
......@@ -274,167 +275,6 @@ class LUOobCommand(NoHooksLU):
utils.CommaJoin(errs))
class _OsQuery(_QueryBase):
FIELDS = query.OS_FIELDS
def ExpandNames(self, lu):
# Lock all nodes in shared mode
# Temporary removal of locks, should be reverted later
# TODO: reintroduce locks when they are lighter-weight
lu.needed_locks = {}
#self.share_locks[locking.LEVEL_NODE] = 1
#self.needed_locks[locking.LEVEL_NODE] = locking.ALL_SET
# The following variables interact with _QueryBase._GetNames
if self.names:
self.wanted = self.names
else:
self.wanted = locking.ALL_SET
self.do_locking = self.use_locking
def DeclareLocks(self, lu, level):
pass
@staticmethod
def _DiagnoseByOS(rlist):
"""Remaps a per-node return list into an a per-os per-node dictionary
@param rlist: a map with node names as keys and OS objects as values
@rtype: dict
@return: a dictionary with osnames as keys and as value another
map, with nodes as keys and tuples of (path, status, diagnose,
variants, parameters, api_versions) as values, eg::
{"debian-etch": {"node1": [(/usr/lib/..., True, "", [], []),
(/srv/..., False, "invalid api")],
"node2": [(/srv/..., True, "", [], [])]}
}
"""
all_os = {}
# we build here the list of nodes that didn't fail the RPC (at RPC
# level), so that nodes with a non-responding node daemon don't
# make all OSes invalid
good_nodes = [node_name for node_name in rlist
if not rlist[node_name].fail_msg]
for node_name, nr in rlist.items():
if nr.fail_msg or not nr.payload:
continue
for (name, path, status, diagnose, variants,
params, api_versions) in nr.payload:
if name not in all_os:
# build a list of nodes for this os containing empty lists
# for each node in node_list
all_os[name] = {}
for nname in good_nodes:
all_os[name][nname] = []
# convert params from [name, help] to (name, help)
params = [tuple(v) for v in params]
all_os[name][node_name].append((path, status, diagnose,
variants, params, api_versions))
return all_os
def _GetQueryData(self, lu):
"""Computes the list of nodes and their attributes.
"""
# Locking is not used
assert not (compat.any(lu.glm.is_owned(level)
for level in locking.LEVELS
if level != locking.LEVEL_CLUSTER) or
self.do_locking or self.use_locking)
valid_nodes = [node.name
for node in lu.cfg.GetAllNodesInfo().values()
if not node.offline and node.vm_capable]
pol = self._DiagnoseByOS(lu.rpc.call_os_diagnose(valid_nodes))
cluster = lu.cfg.GetClusterInfo()
data = {}
for (os_name, os_data) in pol.items():
info = query.OsInfo(name=os_name, valid=True, node_status=os_data,
hidden=(os_name in cluster.hidden_os),
blacklisted=(os_name in cluster.blacklisted_os))
variants = set()
parameters = set()
api_versions = set()
for idx, osl in enumerate(os_data.values()):
info.valid = bool(info.valid and osl and osl[0][1])
if not info.valid:
break
(node_variants, node_params, node_api) = osl[0][3:6]
if idx == 0:
# First entry
variants.update(node_variants)
parameters.update(node_params)
api_versions.update(node_api)
else:
# Filter out inconsistent values
variants.intersection_update(node_variants)
parameters.intersection_update(node_params)
api_versions.intersection_update(node_api)
info.variants = list(variants)
info.parameters = list(parameters)
info.api_versions = list(api_versions)
data[os_name] = info
# Prepare data in requested order
return [data[name] for name in self._GetNames(lu, pol.keys(), None)
if name in data]
class LUOsDiagnose(NoHooksLU):
"""Logical unit for OS diagnose/query.
"""
REQ_BGL = False
@staticmethod
def _BuildFilter(fields, names):
"""Builds a filter for querying OSes.
"""
name_filter = qlang.MakeSimpleFilter("name", names)
# Legacy behaviour: Hide hidden, blacklisted or invalid OSes if the
# respective field is not requested
status_filter = [[qlang.OP_NOT, [qlang.OP_TRUE, fname]]
for fname in ["hidden", "blacklisted"]
if fname not in fields]
if "valid" not in fields:
status_filter.append([qlang.OP_TRUE, "valid"])
if status_filter:
status_filter.insert(0, qlang.OP_AND)
else:
status_filter = None
if name_filter and status_filter:
return [qlang.OP_AND, name_filter, status_filter]
elif name_filter:
return name_filter
else:
return status_filter
def CheckArguments(self):
self.oq = _OsQuery(self._BuildFilter(self.op.output_fields, self.op.names),
self.op.output_fields, False)
def ExpandNames(self):
self.oq.ExpandNames(self)
def Exec(self, feedback_fn):
return self.oq.OldStyleQuery(self)
class _ExtStorageQuery(_QueryBase):
FIELDS = query.EXTSTORAGE_FIELDS
......
#
#
# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Google Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.
"""Logical units dealing with OS."""
from ganeti import compat
from ganeti import locking
from ganeti import qlang
from ganeti import query
from ganeti.cmdlib.base import NoHooksLU, _QueryBase
class _OsQuery(_QueryBase):
FIELDS = query.OS_FIELDS
def ExpandNames(self, lu):
# Lock all nodes in shared mode
# Temporary removal of locks, should be reverted later
# TODO: reintroduce locks when they are lighter-weight
lu.needed_locks = {}
#self.share_locks[locking.LEVEL_NODE] = 1
#self.needed_locks[locking.LEVEL_NODE] = locking.ALL_SET
# The following variables interact with _QueryBase._GetNames
if self.names:
self.wanted = self.names
else:
self.wanted = locking.ALL_SET
self.do_locking = self.use_locking
def DeclareLocks(self, lu, level):
pass
@staticmethod
def _DiagnoseByOS(rlist):
"""Remaps a per-node return list into an a per-os per-node dictionary
@param rlist: a map with node names as keys and OS objects as values
@rtype: dict
@return: a dictionary with osnames as keys and as value another
map, with nodes as keys and tuples of (path, status, diagnose,
variants, parameters, api_versions) as values, eg::
{"debian-etch": {"node1": [(/usr/lib/..., True, "", [], []),
(/srv/..., False, "invalid api")],
"node2": [(/srv/..., True, "", [], [])]}
}
"""
all_os = {}
# we build here the list of nodes that didn't fail the RPC (at RPC
# level), so that nodes with a non-responding node daemon don't
# make all OSes invalid
good_nodes = [node_name for node_name in rlist
if not rlist[node_name].fail_msg]
for node_name, nr in rlist.items():
if nr.fail_msg or not nr.payload:
continue
for (name, path, status, diagnose, variants,
params, api_versions) in nr.payload:
if name not in all_os:
# build a list of nodes for this os containing empty lists
# for each node in node_list
all_os[name] = {}
for nname in good_nodes:
all_os[name][nname] = []
# convert params from [name, help] to (name, help)
params = [tuple(v) for v in params]
all_os[name][node_name].append((path, status, diagnose,
variants, params, api_versions))
return all_os
def _GetQueryData(self, lu):
"""Computes the list of nodes and their attributes.
"""
# Locking is not used
assert not (compat.any(lu.glm.is_owned(level)
for level in locking.LEVELS
if level != locking.LEVEL_CLUSTER) or
self.do_locking or self.use_locking)
valid_nodes = [node.name
for node in lu.cfg.GetAllNodesInfo().values()
if not node.offline and node.vm_capable]
pol = self._DiagnoseByOS(lu.rpc.call_os_diagnose(valid_nodes))
cluster = lu.cfg.GetClusterInfo()
data = {}
for (os_name, os_data) in pol.items():
info = query.OsInfo(name=os_name, valid=True, node_status=os_data,
hidden=(os_name in cluster.hidden_os),
blacklisted=(os_name in cluster.blacklisted_os))
variants = set()
parameters = set()
api_versions = set()
for idx, osl in enumerate(os_data.values()):
info.valid = bool(info.valid and osl and osl[0][1])
if not info.valid:
break
(node_variants, node_params, node_api) = osl[0][3:6]
if idx == 0:
# First entry
variants.update(node_variants)
parameters.update(node_params)
api_versions.update(node_api)
else:
# Filter out inconsistent values
variants.intersection_update(node_variants)
parameters.intersection_update(node_params)
api_versions.intersection_update(node_api)
info.variants = list(variants)
info.parameters = list(parameters)
info.api_versions = list(api_versions)
data[os_name] = info
# Prepare data in requested order
return [data[name] for name in self._GetNames(lu, pol.keys(), None)
if name in data]
class LUOsDiagnose(NoHooksLU):
"""Logical unit for OS diagnose/query.
"""
REQ_BGL = False
@staticmethod
def _BuildFilter(fields, names):
"""Builds a filter for querying OSes.
"""
name_filter = qlang.MakeSimpleFilter("name", names)
# Legacy behaviour: Hide hidden, blacklisted or invalid OSes if the
# respective field is not requested
status_filter = [[qlang.OP_NOT, [qlang.OP_TRUE, fname]]
for fname in ["hidden", "blacklisted"]
if fname not in fields]
if "valid" not in fields:
status_filter.append([qlang.OP_TRUE, "valid"])
if status_filter:
status_filter.insert(0, qlang.OP_AND)
else:
status_filter = None
if name_filter and status_filter:
return [qlang.OP_AND, name_filter, status_filter]
elif name_filter:
return name_filter
else:
return status_filter
def CheckArguments(self):
self.oq = _OsQuery(self._BuildFilter(self.op.output_fields, self.op.names),
self.op.output_fields, False)
def ExpandNames(self):
self.oq.ExpandNames(self)
def Exec(self, feedback_fn):
return self.oq.OldStyleQuery(self)
......@@ -25,7 +25,6 @@ from ganeti import constants
from ganeti import errors
from ganeti import query
from ganeti.cmdlib import _ExtStorageQuery
from ganeti.cmdlib import _OsQuery
from ganeti.cmdlib.backup import _ExportQuery
from ganeti.cmdlib.base import NoHooksLU
from ganeti.cmdlib.cluster import _ClusterQuery
......@@ -33,6 +32,7 @@ from ganeti.cmdlib.group import _GroupQuery
from ganeti.cmdlib.instance import _InstanceQuery
from ganeti.cmdlib.network import _NetworkQuery
from ganeti.cmdlib.node import _NodeQuery
from ganeti.cmdlib.operating_system import _OsQuery
#: Query type implementations
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment