зеркало из https://github.com/microsoft/lisa.git
ready env: use default credential in platform
Previously, it must provide credential for each remote node. With this change, remote node can use credential in platform. So if nodes use the same credentials, it doesn't need to specify one by one. Changes, 1. Remove `with_connection_info` in schema and RemoteNode. The conneciton info won't be validated when loading schema. It's delayed to `set_connection_info`. 2. Add `set_connection_info_by_runbook` with default values. It allows platform to fill default values. 3. Fill in connection information of remote nodes in platform. It can fill default value for remote nodes.
This commit is contained in:
Родитель
4e19421480
Коммит
b1eac83c6a
82
lisa/node.py
82
lisa/node.py
|
@ -242,33 +242,6 @@ class Node(subclasses.BaseClassWithRunbookMixin, ContextMixin, InitializableMixi
|
|||
|
||||
|
||||
class RemoteNode(Node):
|
||||
def __init__(
|
||||
self,
|
||||
runbook: schema.RemoteNode,
|
||||
index: int,
|
||||
logger_name: str,
|
||||
base_log_path: Optional[Path],
|
||||
) -> None:
|
||||
super().__init__(
|
||||
index=index,
|
||||
runbook=runbook,
|
||||
logger_name=logger_name,
|
||||
base_log_path=base_log_path,
|
||||
)
|
||||
|
||||
if self._runbook.with_connection_info:
|
||||
fields = [
|
||||
constants.ENVIRONMENTS_NODES_REMOTE_ADDRESS,
|
||||
constants.ENVIRONMENTS_NODES_REMOTE_PORT,
|
||||
constants.ENVIRONMENTS_NODES_REMOTE_PUBLIC_ADDRESS,
|
||||
constants.ENVIRONMENTS_NODES_REMOTE_PUBLIC_PORT,
|
||||
constants.ENVIRONMENTS_NODES_REMOTE_USERNAME,
|
||||
constants.ENVIRONMENTS_NODES_REMOTE_PASSWORD,
|
||||
constants.ENVIRONMENTS_NODES_REMOTE_PRIVATE_KEY_FILE,
|
||||
]
|
||||
parameters = fields_to_dict(self._runbook, fields)
|
||||
self.set_connection_info(**parameters)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return str(self._connection_info)
|
||||
|
||||
|
@ -284,12 +257,42 @@ class RemoteNode(Node):
|
|||
def type_schema(cls) -> Type[schema.TypedSchema]:
|
||||
return schema.RemoteNode
|
||||
|
||||
def set_connection_info_by_runbook(
|
||||
self,
|
||||
default_username: str = "",
|
||||
default_password: str = "",
|
||||
default_private_key_file: str = "",
|
||||
) -> None:
|
||||
fields = [
|
||||
constants.ENVIRONMENTS_NODES_REMOTE_ADDRESS,
|
||||
constants.ENVIRONMENTS_NODES_REMOTE_PORT,
|
||||
constants.ENVIRONMENTS_NODES_REMOTE_PUBLIC_ADDRESS,
|
||||
constants.ENVIRONMENTS_NODES_REMOTE_PUBLIC_PORT,
|
||||
]
|
||||
parameters = fields_to_dict(self.runbook, fields)
|
||||
|
||||
# use default credential, if they are not specified
|
||||
node_runbook = cast(schema.RemoteNode, self.runbook)
|
||||
parameters[constants.ENVIRONMENTS_NODES_REMOTE_USERNAME] = (
|
||||
node_runbook.username if node_runbook.username else default_username
|
||||
)
|
||||
parameters[constants.ENVIRONMENTS_NODES_REMOTE_PASSWORD] = (
|
||||
node_runbook.password if node_runbook.password else default_password
|
||||
)
|
||||
parameters[constants.ENVIRONMENTS_NODES_REMOTE_PRIVATE_KEY_FILE] = (
|
||||
node_runbook.private_key_file
|
||||
if node_runbook.private_key_file
|
||||
else default_private_key_file
|
||||
)
|
||||
|
||||
self.set_connection_info(**parameters)
|
||||
|
||||
def set_connection_info(
|
||||
self,
|
||||
address: str = "",
|
||||
port: int = 22,
|
||||
port: Optional[int] = 22,
|
||||
public_address: str = "",
|
||||
public_port: int = 22,
|
||||
public_port: Optional[int] = 22,
|
||||
username: str = "root",
|
||||
password: str = "",
|
||||
private_key_file: str = "",
|
||||
|
@ -299,6 +302,25 @@ class RemoteNode(Node):
|
|||
"node is set connection information already, cannot set again"
|
||||
)
|
||||
|
||||
if not address and not public_address:
|
||||
raise LisaException(
|
||||
"at least one of address and public_address need to be set"
|
||||
)
|
||||
elif not address:
|
||||
address = public_address
|
||||
elif not public_address:
|
||||
public_address = address
|
||||
|
||||
if not port and not public_port:
|
||||
raise LisaException("at least one of port and public_port need to be set")
|
||||
elif not port:
|
||||
port = public_port
|
||||
elif not public_port:
|
||||
public_port = port
|
||||
|
||||
assert public_port
|
||||
assert port
|
||||
|
||||
self._connection_info = ConnectionInfo(
|
||||
public_address,
|
||||
public_port,
|
||||
|
@ -307,6 +329,7 @@ class RemoteNode(Node):
|
|||
private_key_file,
|
||||
)
|
||||
self._shell = SshShell(self._connection_info)
|
||||
|
||||
self.public_address = public_address
|
||||
self.public_port = public_port
|
||||
self.internal_address = address
|
||||
|
@ -468,7 +491,6 @@ class Nodes:
|
|||
type=constants.ENVIRONMENTS_NODES_REMOTE,
|
||||
capability=min_requirement,
|
||||
is_default=node_requirement.is_default,
|
||||
with_connection_info=False,
|
||||
)
|
||||
node = Node.create(
|
||||
index=len(self._list),
|
||||
|
|
|
@ -4,11 +4,12 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from functools import partial
|
||||
from typing import Any, Dict, List, Type
|
||||
from typing import Any, Dict, List, Type, cast
|
||||
|
||||
from lisa import schema
|
||||
from lisa.environment import Environment, EnvironmentStatus
|
||||
from lisa.feature import Feature, Features
|
||||
from lisa.node import RemoteNode
|
||||
from lisa.util import (
|
||||
InitializableMixin,
|
||||
LisaException,
|
||||
|
@ -108,6 +109,19 @@ class Platform(subclasses.BaseClassWithRunbookMixin, InitializableMixin):
|
|||
self.initialize()
|
||||
|
||||
log = get_logger(f"prepare[{environment.name}]", parent=self._log)
|
||||
|
||||
# check and fill connection information for RemoteNode. So that the
|
||||
# RemoteNodes can share the same connection information with created
|
||||
# nodes.
|
||||
platform_runbook = cast(schema.Platform, self.runbook)
|
||||
for node in environment.nodes.list():
|
||||
if isinstance(node, RemoteNode):
|
||||
node.set_connection_info_by_runbook(
|
||||
default_username=platform_runbook.admin_username,
|
||||
default_password=platform_runbook.admin_password,
|
||||
default_private_key_file=platform_runbook.admin_private_key_file,
|
||||
)
|
||||
|
||||
is_success = self._prepare_environment(environment, log)
|
||||
if is_success:
|
||||
environment.status = EnvironmentStatus.Prepared
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
# Licensed under the MIT license.
|
||||
|
||||
import copy
|
||||
from dataclasses import InitVar, dataclass, field
|
||||
from dataclasses import dataclass, field
|
||||
from enum import Enum
|
||||
from typing import Any, Callable, Dict, List, Optional, Type, TypeVar, Union, cast
|
||||
|
||||
|
@ -617,50 +617,15 @@ class RemoteNode(Node):
|
|||
default=22,
|
||||
metadata=metadata(validate=validate.Range(min=1, max=65535)),
|
||||
)
|
||||
username: str = field(default="", metadata=metadata(required=True))
|
||||
username: str = ""
|
||||
password: str = ""
|
||||
private_key_file: str = ""
|
||||
|
||||
with_connection_info: InitVar[bool] = True
|
||||
|
||||
def __post_init__(self, *args: Any, **kwargs: Any) -> None:
|
||||
if self.delay_parsed:
|
||||
# the self needs to be overridden, since it's saved to delay parsed fields.
|
||||
self.with_connection_info = self.delay_parsed.get(
|
||||
"with_connection_info", True
|
||||
)
|
||||
else:
|
||||
self.with_connection_info = True
|
||||
if self.with_connection_info:
|
||||
# if there is connection info, then validate it.
|
||||
self.update_connection_info()
|
||||
|
||||
def update_connection_info(self) -> None:
|
||||
add_secret(self.username, PATTERN_HEADTAIL)
|
||||
add_secret(self.password)
|
||||
add_secret(self.private_key_file)
|
||||
|
||||
if not self.address and not self.public_address:
|
||||
raise LisaException(
|
||||
"at least one of address and public_address need to be set"
|
||||
)
|
||||
elif not self.address:
|
||||
self.address = self.public_address
|
||||
elif not self.public_address:
|
||||
self.public_address = self.address
|
||||
|
||||
if not self.port and not self.public_port:
|
||||
raise LisaException("at least one of port and public_port need to be set")
|
||||
elif not self.port:
|
||||
self.port = self.public_port
|
||||
elif not self.public_port:
|
||||
self.public_port = self.port
|
||||
|
||||
if not self.password and not self.private_key_file:
|
||||
raise LisaException(
|
||||
"at least one of password or private_key_file need to be set in schema"
|
||||
)
|
||||
|
||||
|
||||
@dataclass_json()
|
||||
@dataclass
|
||||
|
|
Загрузка…
Ссылка в новой задаче