Skip to content

Commit eca9d79

Browse files
sambacc: support passing an opener for join source files
Allow passing of URIs in addition to local paths for the Joiner type by supporting an optional opener argument to the Joiner. Signed-off-by: John Mulligan <[email protected]>
1 parent 7dee55e commit eca9d79

File tree

1 file changed

+47
-12
lines changed

1 file changed

+47
-12
lines changed

sambacc/join.py

Lines changed: 47 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,13 @@
1717
#
1818

1919
import enum
20+
import errno
2021
import json
2122
import logging
2223
import subprocess
2324
import typing
2425

26+
from .opener import Opener, FileOpener
2527
from sambacc import samba_cmds
2628
from sambacc.simple_waiter import Waiter
2729

@@ -62,6 +64,12 @@ def __init__(
6264
self.password = password
6365

6466

67+
class _JoinSource(typing.NamedTuple):
68+
method: JoinBy
69+
upass: typing.Optional[UserPass]
70+
path: str
71+
72+
6573
class Joiner:
6674
"""Utility class for joining to AD domain.
6775
@@ -71,9 +79,16 @@ class Joiner:
7179

7280
_net_ads_join = samba_cmds.net["ads", "join"]
7381

74-
def __init__(self, marker: typing.Optional[str] = None) -> None:
75-
self._sources: list[tuple[JoinBy, typing.Any]] = []
82+
def __init__(
83+
self,
84+
marker: typing.Optional[str] = None,
85+
*,
86+
opener: typing.Optional[Opener] = None,
87+
) -> None:
88+
self._source_paths: list[str] = []
89+
self._sources: list[_JoinSource] = []
7690
self.marker = marker
91+
self._opener = opener or FileOpener()
7792

7893
def add_source(
7994
self,
@@ -83,27 +98,43 @@ def add_source(
8398
if method in {JoinBy.PASSWORD, JoinBy.INTERACTIVE}:
8499
if not isinstance(value, UserPass):
85100
raise ValueError("expected UserPass value")
101+
if method == JoinBy.PASSWORD:
102+
self.add_pw_source(value)
103+
else:
104+
self.add_interactive_source(value)
86105
elif method in {JoinBy.FILE}:
87106
if not isinstance(value, str):
88107
raise ValueError("expected str value")
108+
self.add_file_source(value)
89109
else:
90110
raise ValueError(f"invalid method: {method}")
91-
self._sources.append((method, value))
111+
112+
def add_file_source(self, path_or_uri: str) -> None:
113+
self._sources.append(_JoinSource(JoinBy.FILE, None, path_or_uri))
114+
115+
def add_pw_source(self, value: UserPass) -> None:
116+
self._sources.append(_JoinSource(JoinBy.PASSWORD, value, ""))
117+
118+
def add_interactive_source(self, value: UserPass) -> None:
119+
self._sources.append(_JoinSource(JoinBy.INTERACTIVE, value, ""))
92120

93121
def join(self, dns_updates: bool = False) -> None:
94122
if not self._sources:
95123
raise JoinError("no sources for join data")
96124
errors = []
97-
for method, value in self._sources:
125+
for src in self._sources:
98126
try:
99-
if method is JoinBy.PASSWORD:
100-
upass = value
101-
elif method is JoinBy.FILE:
102-
upass = self._read_from(value)
103-
elif method is JoinBy.INTERACTIVE:
104-
upass = UserPass(value.username, _PROMPT)
127+
if src.method is JoinBy.PASSWORD:
128+
assert src.upass
129+
upass = src.upass
130+
elif src.method is JoinBy.FILE:
131+
assert src.path
132+
upass = self._read_from(src.path)
133+
elif src.method is JoinBy.INTERACTIVE:
134+
assert src.upass
135+
upass = UserPass(src.upass.username, _PROMPT)
105136
else:
106-
raise ValueError(f"invalid method: {method}")
137+
raise ValueError(f"invalid method: {src.method}")
107138
self._join(upass, dns_updates=dns_updates)
108139
self._set_marker()
109140
return
@@ -118,10 +149,14 @@ def join(self, dns_updates: bool = False) -> None:
118149

119150
def _read_from(self, path: str) -> UserPass:
120151
try:
121-
with open(path) as fh:
152+
with self._opener.open(path) as fh:
122153
data = json.load(fh)
123154
except FileNotFoundError:
124155
raise JoinError(f"source file not found: {path}")
156+
except OSError as err:
157+
if getattr(err, "errno", 0) != errno.ENOENT:
158+
raise
159+
raise JoinError(f"resource not found: {path}")
125160
upass = UserPass()
126161
try:
127162
upass.username = data["username"]

0 commit comments

Comments
 (0)