manila/manila/share/drivers/container/protocol_helper.py

156 lines
5.9 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.
from oslo_log import log
from manila.common import constants as const
from manila import exception
from manila.i18n import _
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):
export_locations = []
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]
)
# TODO(tbarron): pass configured address family when we support IPv6
addresses = self.container.fetch_container_addresses(
server_id, address_family="inet")
for address in addresses:
export_location = {
"is_admin_only": False,
"path": "//%(ip_address)s/%(share_name)s" %
{
"ip_address": address,
"share_name": share_name
},
"preferred": False
}
export_locations.append(export_location)
return export_locations
def delete_share(self, server_id, share_name, ignore_errors=False):
self.container.execute(
server_id,
["net", "conf", "delshare", share_name],
ignore_errors=ignore_errors
)
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],
ignore_errors=True
)
if result:
return result[0].rstrip('\n')
else:
return ""
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("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, share_name, 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)
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)