Skip to content

Commit 3cb14d6

Browse files
authored
Merge pull request ceph#62362 from phlogistonjohn/jjm-mgr-smb-tweaks
mgr/smb: additional input and output controls Reviewed-by: Avan Thakkar <[email protected]> Reviewed-by: Sachin Prabhu <[email protected]>
2 parents 447a182 + fa4f9c1 commit 3cb14d6

File tree

6 files changed

+367
-18
lines changed

6 files changed

+367
-18
lines changed

doc/mgr/smb.rst

Lines changed: 82 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ Create Cluster
5555

5656
.. code:: bash
5757
58-
$ ceph smb cluster create <cluster_id> {user|active-directory} [--domain-realm=<domain_realm>] [--domain-join-user-pass=<domain_join_user_pass>] [--define-user-pass=<define_user_pass>] [--custom-dns=<custom_dns>] [--placement=<placement>] [--clustering=<clustering>]
58+
$ ceph smb cluster create <cluster_id> {user|active-directory} [--domain-realm=<domain_realm>] [--domain-join-user-pass=<domain_join_user_pass>] [--define-user-pass=<define_user_pass>] [--custom-dns=<custom_dns>] [--placement=<placement>] [--clustering=<clustering>] [--password-filter=<password_filter>] [--password-filter-out=<password_filter_out>]
5959
6060
Create a new logical cluster, identified by the cluster id value. The cluster
6161
create command must specify the authentication mode the cluster will use. This
@@ -101,16 +101,40 @@ public_addrs
101101
Supported only when using Samba's clustering. Assign "virtual" IP
102102
addresses that will be managed by the clustering subsystem and may automatically
103103
move between nodes running Samba containers.
104+
password_filter
105+
One of ``none`` or ``base64``. If the filter is ``none`` the password
106+
values on the command line are assumed to be plain text. If the filter is
107+
``base64`` the password values are assumed to be obscured with
108+
base64 encoding the string. If ``--password-filter-out`` is not specified
109+
this filter will also be applied to the output.
110+
password_filter_out
111+
One of ``none``, ``base64``, or ``hidden``. If the filter is ``none`` the
112+
password fields in the output are emitted as plain text. If the filter is
113+
``base64`` password fields will be obscured by base64 encoding the
114+
string. If the filter is ``hidden`` the password values will be replaced
115+
by a invalid generic replacement string containing only asterisks.
104116

105117
Remove Cluster
106118
++++++++++++++
107119

108120
.. code:: bash
109121
110-
$ ceph smb cluster rm <cluster_id>
122+
$ ceph smb cluster rm <cluster_id> [--password-filter=<password_filter>]
111123
112124
Remove a logical SMB cluster from the Ceph cluster.
113125

126+
Options:
127+
128+
cluster_id
129+
A ``cluster_id`` value identifying a cluster resource.
130+
password_filter
131+
One of ``none``, ``base64``, or ``hidden``. If the filter is ``none`` the
132+
password fields in the output are emitted as plain text. If the filter is
133+
``base64`` password fields will be obscured by base64 encoding the
134+
string. If the filter is ``hidden`` the password values will be replaced
135+
by a invalid generic replacement string containing only asterisks.
136+
137+
114138
List Clusters
115139
++++++++++++++
116140

@@ -190,15 +214,68 @@ command, for example:
190214
191215
$ ceph smb apply -i /path/to/resources.yaml
192216
217+
In addition to the resource specification the ``apply`` sub-command accepts
218+
options that control how the input and output of the command behave:
219+
220+
.. code:: bash
221+
222+
$ ceph smb apply [--format=<format>] [--password-filter=<password_filter>] [--password-filter-out=<password_filter_out>] -i <input>
223+
224+
Options:
225+
226+
format
227+
One of ``json`` (the default) or ``yaml``. Output format can be
228+
selected independent of the input format.
229+
password_filter
230+
One of ``none`` or ``base64``. If the filter is ``none`` the password
231+
fields in the input are assumed to be plain text. If the filter is
232+
``base64`` the password fields are assumed to be obscured with
233+
base64 encoding the string. If ``--password-filter-out`` is not specified
234+
this filter will also be applied to the output.
235+
password_filter_out
236+
One of ``none``, ``base64``, or ``hidden``. If the filter is ``none`` the
237+
password fields in the output are emitted as plain text. If the filter is
238+
``base64`` password fields will be obscured by base64 encoding the
239+
string. If the filter is ``hidden`` the password values will be replaced
240+
by a invalid generic replacement string containing only asterisks.
241+
input
242+
A file name or ``-`` to use stdin.
243+
244+
193245
Resources that have already been applied to the Ceph cluster configuration can
194246
be viewed using the ``ceph smb show`` command. For example:
195247

196248
.. code:: bash
197249
198-
$ ceph smb show [<resource_name>...]
250+
$ ceph smb show ceph.smb.cluster.cluster1
251+
252+
The ``show`` command can show all resources, resources of a given type, or specific
253+
resource items. Options can be provided that control the output of the command.
254+
255+
.. code:: bash
256+
257+
$ ceph smb show [resource_name...] [--format=<format>] [--results=<results>] [--password-filter=<password_filter>]
258+
259+
Options:
199260

200-
The ``show`` command can show all resources of a given type or specific
201-
resources by id. ``resource_name`` arguments can take the following forms:
261+
resource_name
262+
One or more strings specifying a resource or resource type. See description below.
263+
format
264+
One of ``json`` (the default) or ``yaml``.
265+
results
266+
One of ``collapsed`` (the default) or ``full``. When set to ``collapsed``
267+
the output of the command will show only the resource JSON/YAML of
268+
a single item if a single item is found. When set to ``full`` even if a
269+
single item is found the output will always include a wrapper object like
270+
(in pseudo-JSON): ``{"resources": [...Resource objects...]}``.
271+
password_filter
272+
One of ``none``, ``base64``, or ``hidden``. If the filter is ``none`` the
273+
password fields in the output are emitted as plain text. If the filter is
274+
``base64`` password fields will be obscured by base64 encoding the
275+
string. If the filter is ``hidden`` the password values will be replaced
276+
by a invalid generic replacement string containing only asterisks.
277+
278+
``resource_name`` arguments can take the following forms:
202279

203280
- ``ceph.smb.cluster``: show all cluster resources
204281
- ``ceph.smb.cluster.<cluster_id>``: show specific cluster with given cluster id

src/pybind/mgr/smb/enums.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,3 +102,30 @@ class SMBClustering(_StrEnum):
102102
DEFAULT = 'default'
103103
ALWAYS = 'always'
104104
NEVER = 'never'
105+
106+
107+
class ShowResults(_StrEnum):
108+
FULL = 'full'
109+
COLLAPSED = 'collapsed'
110+
111+
112+
class PasswordFilter(_StrEnum):
113+
"""Filter type for password values."""
114+
115+
NONE = 'none'
116+
BASE64 = 'base64'
117+
HIDDEN = 'hidden'
118+
119+
120+
class InputPasswordFilter(_StrEnum):
121+
"""Filter type for input password values."""
122+
123+
NONE = 'none'
124+
BASE64 = 'base64'
125+
126+
def to_password_filter(self) -> PasswordFilter:
127+
"""Convert input password filter to password filter type."""
128+
# This is because python doesn't allow extending enums (with values)
129+
# but we want a InputPasswordFilter to be a strict subset of the
130+
# password filter enum.
131+
return PasswordFilter(self.value)

src/pybind/mgr/smb/module.py

Lines changed: 72 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@
2020
)
2121
from .enums import (
2222
AuthMode,
23+
InputPasswordFilter,
2324
JoinSourceType,
25+
PasswordFilter,
26+
ShowResults,
2427
SMBClustering,
2528
UserGroupSourceType,
2629
)
@@ -139,13 +142,49 @@ def internal_store_backend(self) -> str:
139142
self.get_module_option('internal_store_backend', ''),
140143
)
141144

145+
def _apply_res(
146+
self,
147+
resource_input: List[resources.SMBResource],
148+
create_only: bool = False,
149+
password_filter: InputPasswordFilter = InputPasswordFilter.NONE,
150+
password_filter_out: Optional[PasswordFilter] = None,
151+
) -> results.ResultGroup:
152+
in_pf = password_filter.to_password_filter() # update enum type
153+
# use the same filtering as the input unless expliclitly set
154+
out_pf = password_filter_out if password_filter_out else in_pf
155+
if in_pf is not PasswordFilter.NONE:
156+
in_op = (in_pf, PasswordFilter.NONE)
157+
log.debug('Password filtering for resource apply: %r', in_op)
158+
resource_input = [r.convert(in_op) for r in resource_input]
159+
all_results = self._handler.apply(
160+
resource_input, create_only=create_only
161+
)
162+
if out_pf is not PasswordFilter.NONE:
163+
# we need to apply the conversion filter to the output
164+
# resources in the results - otherwise we would show raw
165+
# passwords - this will be the inverse of the filter applied to
166+
# the input
167+
out_op = (PasswordFilter.NONE, out_pf)
168+
log.debug('Password filtering for smb apply output: %r', in_op)
169+
all_results = all_results.convert_results(out_op)
170+
return all_results
171+
142172
@cli.SMBCommand('apply', perm='rw')
143-
def apply_resources(self, inbuf: str) -> results.ResultGroup:
173+
def apply_resources(
174+
self,
175+
inbuf: str,
176+
password_filter: InputPasswordFilter = InputPasswordFilter.NONE,
177+
password_filter_out: Optional[PasswordFilter] = None,
178+
) -> results.ResultGroup:
144179
"""Create, update, or remove smb configuration resources based on YAML
145180
or JSON specs
146181
"""
147182
try:
148-
return self._handler.apply(resources.load_text(inbuf))
183+
return self._apply_res(
184+
resources.load_text(inbuf),
185+
password_filter=password_filter,
186+
password_filter_out=password_filter_out,
187+
)
149188
except resources.InvalidResourceError as err:
150189
# convert the exception into a result and return it as the only
151190
# item in the result group
@@ -172,6 +211,8 @@ def cluster_create(
172211
placement: Optional[str] = None,
173212
clustering: Optional[SMBClustering] = None,
174213
public_addrs: Optional[List[str]] = None,
214+
password_filter: InputPasswordFilter = InputPasswordFilter.NONE,
215+
password_filter_out: Optional[PasswordFilter] = None,
175216
) -> results.Result:
176217
"""Create an smb cluster"""
177218
domain_settings = None
@@ -282,13 +323,24 @@ def cluster_create(
282323
public_addrs=c_public_addrs,
283324
)
284325
to_apply.append(cluster)
285-
return self._handler.apply(to_apply, create_only=True).squash(cluster)
326+
return self._apply_res(
327+
to_apply,
328+
create_only=True,
329+
password_filter=password_filter,
330+
password_filter_out=password_filter_out,
331+
).squash(cluster)
286332

287333
@cli.SMBCommand('cluster rm', perm='rw')
288-
def cluster_rm(self, cluster_id: str) -> results.Result:
334+
def cluster_rm(
335+
self,
336+
cluster_id: str,
337+
password_filter: PasswordFilter = PasswordFilter.NONE,
338+
) -> results.Result:
289339
"""Remove an smb cluster"""
290340
cluster = resources.RemovedCluster(cluster_id=cluster_id)
291-
return self._handler.apply([cluster]).one()
341+
return self._apply_res(
342+
[cluster], password_filter_out=password_filter
343+
).one()
292344

293345
@cli.SMBCommand('share ls', perm='r')
294346
def share_ls(self, cluster_id: str) -> List[str]:
@@ -324,18 +376,23 @@ def share_create(
324376
subvolume=subvolume,
325377
),
326378
)
327-
return self._handler.apply([share], create_only=True).one()
379+
return self._apply_res([share], create_only=True).one()
328380

329381
@cli.SMBCommand('share rm', perm='rw')
330382
def share_rm(self, cluster_id: str, share_id: str) -> results.Result:
331383
"""Remove an smb share"""
332384
share = resources.RemovedShare(
333385
cluster_id=cluster_id, share_id=share_id
334386
)
335-
return self._handler.apply([share]).one()
387+
return self._apply_res([share]).one()
336388

337-
@cli.SMBCommand('show', perm='r')
338-
def show(self, resource_names: Optional[List[str]] = None) -> Simplified:
389+
@cli.SMBCommand("show", perm="r")
390+
def show(
391+
self,
392+
resource_names: Optional[List[str]] = None,
393+
results: ShowResults = ShowResults.COLLAPSED,
394+
password_filter: PasswordFilter = PasswordFilter.NONE,
395+
) -> Simplified:
339396
"""Show resources fetched from the local config store based on resource
340397
type or resource type and id(s).
341398
"""
@@ -346,9 +403,13 @@ def show(self, resource_names: Optional[List[str]] = None) -> Simplified:
346403
resources = self._handler.matching_resources(resource_names)
347404
except handler.InvalidResourceMatch as err:
348405
raise cli.InvalidInputValue(str(err)) from err
349-
if len(resources) == 1:
406+
if password_filter is not PasswordFilter.NONE:
407+
op = (PasswordFilter.NONE, password_filter)
408+
log.debug('Password filtering for smb show: %r', op)
409+
resources = [r.convert(op) for r in resources]
410+
if len(resources) == 1 and results is ShowResults.COLLAPSED:
350411
return resources[0].to_simplified()
351-
return {'resources': [r.to_simplified() for r in resources]}
412+
return {"resources": [r.to_simplified() for r in resources]}
352413

353414
def submit_smb_spec(self, spec: SMBSpec) -> None:
354415
"""Submit a new or updated smb spec object to ceph orchestration."""

0 commit comments

Comments
 (0)