Merge pull request #1568 from CarlosNihelton/ad-enhancements-deeng-596

Active Directory API UX Enhancements
This commit is contained in:
Carlos Nihelton 2023-02-18 00:12:16 -03:00 committed by GitHub
commit bf603d3b3e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 55 additions and 2 deletions

View File

@ -418,6 +418,12 @@ class API:
# POST expects input validated by the check methods below:
def POST(data: Payload[ADConnectionInfo]) -> None: ...
class has_support:
""" Whether the live system supports Active Directory or not.
Network status is not considered.
Clients should call this before showing the AD page. """
def GET() -> bool: ...
class check_domain_name:
def GET(domain_name: Payload[str]) \
-> List[AdDomainNameValidation]: ...

View File

@ -27,6 +27,16 @@ class ADModel:
self.do_join = False
self.conn_info: Optional[ADConnectionInfo] = None
def set_domain(self, domain: str):
if not domain:
return
if self.conn_info:
self.conn_info.domain_name = domain
else:
self.conn_info = ADConnectionInfo(domain_name=domain)
async def target_packages(self):
# NOTE Those packages must be present in the target system to allow
# joining to a domain.

View File

@ -14,9 +14,11 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
import os
import re
from typing import List, Optional, Set
from subiquitycore.utils import arun_command
from subiquitycore.async_helpers import run_bg_task
from subiquity.common.apidef import API
from subiquity.common.types import (
@ -43,6 +45,9 @@ class DcPingStrategy:
cmd = "/usr/sbin/realm"
arg = "discover"
def has_support(self) -> bool:
return os.access(self.cmd, os.X_OK)
async def ping(self, address: str) -> AdDomainNameValidation:
cp = await arun_command([self.cmd, self.arg, address], env={})
if cp.returncode:
@ -50,6 +55,18 @@ class DcPingStrategy:
return AdDomainNameValidation.OK
async def discover(self) -> str:
""" Attempts to discover a domain through the network.
Returns the domain or an empty string on error. """
cp = await arun_command([self.cmd, self.arg], env={})
discovered = ""
if cp.returncode == 0:
# A typical output looks like:
# 'creative.com\n type: kerberos\n realm-name: CREATIVE.COM\n...'
discovered = cp.stdout.split('\n')[0].strip()
return discovered
class StubDcPingStrategy(DcPingStrategy):
""" For testing purpose. This class doesn't talk to the network.
@ -63,6 +80,12 @@ class StubDcPingStrategy(DcPingStrategy):
return AdDomainNameValidation.OK
async def discover(self) -> str:
return "ubuntu.com"
def has_support(self) -> bool:
return True
class ADController(SubiquityController):
""" Implements the server part of the Active Directory feature. """
@ -77,6 +100,15 @@ class ADController(SubiquityController):
else:
self.ping_strgy = DcPingStrategy()
def start(self):
if self.ping_strgy.has_support():
run_bg_task(self._try_discover_domain())
async def _try_discover_domain(self):
discovered_domain = await self.ping_strgy.discover()
if discovered_domain:
self.model.set_domain(discovered_domain)
async def GET(self) -> Optional[ADConnectionInfo]:
"""Returns the currently configured AD settings"""
return self.model.conn_info
@ -104,6 +136,11 @@ class ADController(SubiquityController):
async def check_password_GET(self, password: str) -> AdPasswordValidation:
return AdValidators.password(password)
async def has_support_GET(self) -> bool:
""" Returns True if the executables required
to configure AD are present in the live system."""
return self.ping_strgy.has_support()
# Helper out-of-class functions grouped.
class AdValidators:

View File

@ -1659,8 +1659,8 @@ class TestActiveDirectory(TestAPI):
async with start_server('examples/simple.json') as instance:
endpoint = '/active_directory'
ad_dict = await instance.get(endpoint)
# Starts empty
self.assertIsNone(ad_dict)
# Starts with the detected domain.
self.assertEqual('ubuntu.com', ad_dict['domain_name'])
# Post works by "returning None"
ad_dict = {