Source code for ironic.common.kernel_parameters
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from dataclasses import dataclass
from ironic.common.exception import InvalidParameterValue
from ironic.common.i18n import _
from ironic.common.kernel_parameter_parser.kernel_parameter_parser \
import Lark_StandAlone
from ironic.common.kernel_parameter_parser.kernel_parameter_parser \
import LarkError
from ironic.common.kernel_parameter_parser.kernel_parameter_parser \
import Transformer
from ironic.common.kernel_parameter_parser.kernel_parameter_parser \
import UnexpectedInput
[docs]def sanitize_kernel_command_line(command_line: str) -> str:
"""Applies filtering to a command line to sanitize it.
NOTE: This does not guarantee a correct or safe kernel command line,
for stronger guarantees of correctness and safety use
KernelCommandLine.parse().
:param command_line: A string containing a kernel command line or
individual parameters.
:returns: A filtered string which should be safer for use.
"""
return ''.join(c for c in command_line if c not in {'\n', '\r', '\0'})
KernelParameterParser = Lark_StandAlone(debug=True)
[docs]@dataclass(frozen=True)
class ParameterKey:
key: str
def __str__(self):
return self.key
[docs]@dataclass(frozen=True)
class ParameterValue:
value: str
def __str__(self):
if ' ' in self.value:
return f"\"{self.value}\""
return self.value
[docs]@dataclass(frozen=True)
class KernelParameter:
key: ParameterKey
value: ParameterValue
def __str__(self):
if len(self.value.value) > 0:
return f"{self.key.key}={self.value.value}"
return self.key.key
_INIT_ARG_PREAMBLE = " -- "
# NOTE(clif): We're handling init args here instead of inside the grammar
# because Lark's stand-alone LALR(1) parser can't handle it.
def _divide_command_line_by_init_args(command_line: str) -> tuple[str, str]:
index = command_line.rfind(_INIT_ARG_PREAMBLE)
if index == -1:
return (command_line, '')
return (command_line[:index],
command_line[index + len(_INIT_ARG_PREAMBLE):])
[docs]@dataclass(frozen=True)
class KernelCommandLine:
parameters: dict[str, list[KernelParameter]]
init_args: str
def __str__(self):
output = ' '.join(
' '.join(str(param) for param in param_list)
for param_list in self.parameters.values())
if len(self.init_args) > 0:
output += _INIT_ARG_PREAMBLE + self.init_args
return output
[docs] @classmethod
def parse(cls, command_line: str):
try:
cmd_line, init_args = \
_divide_command_line_by_init_args(command_line)
tree = KernelParameterParser.parse(cmd_line)
kcl = KernelParameterTransformer().transform(tree)
return KernelCommandLine(kcl.parameters, init_args)
except (LarkError, UnexpectedInput) as e:
raise InvalidParameterValue(
_('Kernel command line did not parse: "%s" -- %s')
% (command_line, str(e))) from None