144 lines
5.5 KiB
Python
144 lines
5.5 KiB
Python
# Copyright (c) 2016 Mirantis, Inc.
|
|
# All Rights Reserved.
|
|
#
|
|
# 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.
|
|
|
|
import re
|
|
|
|
from oslo_log import log
|
|
|
|
from manila.common import constants as const
|
|
from manila import exception
|
|
from manila.i18n import _, _LW
|
|
|
|
LOG = log.getLogger(__name__)
|
|
|
|
|
|
class DockerCIFSHelper(object):
|
|
def __init__(self, container_helper, *args, **kwargs):
|
|
super(DockerCIFSHelper, self).__init__()
|
|
self.share = kwargs.get("share")
|
|
self.conf = kwargs.get("config")
|
|
self.container = container_helper
|
|
|
|
def create_share(self, server_id):
|
|
share_name = self.share.share_id
|
|
cmd = ["net", "conf", "addshare", share_name,
|
|
"/shares/%s" % share_name, "writeable=y"]
|
|
if self.conf.container_cifs_guest_ok:
|
|
cmd.append("guest_ok=y")
|
|
else:
|
|
cmd.append("guest_ok=n")
|
|
self.container.execute(server_id, cmd)
|
|
parameters = {
|
|
"browseable": "yes",
|
|
"create mask": "0755",
|
|
"read only": "no",
|
|
}
|
|
for param, value in parameters.items():
|
|
self.container.execute(
|
|
server_id,
|
|
["net", "conf", "setparm", share_name, param, value]
|
|
)
|
|
result = self.container.execute(
|
|
server_id,
|
|
["ip", "addr", "show", "eth0"]
|
|
)[0].split('\n')[2]
|
|
address = re.findall("\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}", result)[0]
|
|
return r"//%(addr)s/%(name)s" % {"addr": address, "name": share_name}
|
|
|
|
def delete_share(self, server_id):
|
|
self.container.execute(
|
|
server_id,
|
|
["net", "conf", "delshare", self.share.share_id]
|
|
)
|
|
|
|
def _get_access_group(self, access_level):
|
|
if access_level == const.ACCESS_LEVEL_RO:
|
|
access = "read list"
|
|
elif access_level == const.ACCESS_LEVEL_RW:
|
|
access = "valid users"
|
|
else:
|
|
raise exception.InvalidShareAccessLevel(level=access_level)
|
|
return access
|
|
|
|
def _get_existing_users(self, server_id, share_name, access):
|
|
result = self.container.execute(
|
|
server_id,
|
|
["net", "conf", "getparm", share_name, access]
|
|
)[0].rstrip('\n')
|
|
return result
|
|
|
|
def _set_users(self, server_id, share_name, access, users_to_set):
|
|
self.container.execute(
|
|
server_id,
|
|
["net", "conf", "setparm", share_name, access, users_to_set]
|
|
)
|
|
|
|
def _allow_access(self, share_name, server_id, user_to_allow,
|
|
access_level):
|
|
access = self._get_access_group(access_level)
|
|
try:
|
|
existing_users = self._get_existing_users(server_id, share_name,
|
|
access)
|
|
except TypeError:
|
|
users_to_allow = user_to_allow
|
|
else:
|
|
users_to_allow = " ".join([existing_users, user_to_allow])
|
|
self._set_users(server_id, share_name, access, users_to_allow)
|
|
|
|
def _deny_access(self, share_name, server_id, user_to_deny,
|
|
access_level):
|
|
access = self._get_access_group(access_level)
|
|
try:
|
|
existing_users = self._get_existing_users(server_id, share_name,
|
|
access)
|
|
except TypeError:
|
|
LOG.warning(_LW("Can't access smbd at share %s.") % share_name)
|
|
return
|
|
else:
|
|
allowed_users = " ".join(sorted(set(existing_users.split()) -
|
|
set([user_to_deny])))
|
|
if allowed_users != existing_users:
|
|
self._set_users(server_id, share_name, access, allowed_users)
|
|
|
|
def update_access(self, server_id, access_rules,
|
|
add_rules=None, delete_rules=None):
|
|
|
|
def _rule_updater(rules, action, override_type_check=False):
|
|
for rule in rules:
|
|
access_level = rule['access_level']
|
|
access_type = rule['access_type']
|
|
# (aovchinnikov): override_type_check is used to ensure
|
|
# broken rules deletion.
|
|
if access_type == 'user' or override_type_check:
|
|
action(share_name, server_id, rule['access_to'],
|
|
access_level)
|
|
else:
|
|
msg = _("Access type '%s' is not supported by the "
|
|
"driver.") % access_type
|
|
raise exception.InvalidShareAccess(reason=msg)
|
|
|
|
share_name = self.share.share_id
|
|
if not (add_rules or delete_rules):
|
|
# clean all users first.
|
|
self.container.execute(
|
|
server_id,
|
|
["net", "conf", "setparm", share_name, "valid users", ""]
|
|
)
|
|
_rule_updater(access_rules or [], self._allow_access)
|
|
return
|
|
_rule_updater(add_rules or [], self._allow_access)
|
|
_rule_updater(delete_rules or [], self._deny_access,
|
|
override_type_check=True)
|