Support Trilio 4.2 Share hashes
The Trilio 4.2 changes the way that hashes are generated for nfs mount points. The hash is now generated from the directory only, the source IP address is ignored. This patch updates the ghost-share action to accommodate that. Change-Id: I64a1cc95a3a78ce79d57f5b840edb29996f04f9c
This commit is contained in:
parent
d0c540a651
commit
055fb499b8
|
@ -25,6 +25,7 @@ from charms_openstack.plugins.trilio import (
|
|||
TrilioVaultCharm,
|
||||
TrilioVaultSubordinateCharm,
|
||||
TrilioVaultCharmGhostAction,
|
||||
TrilioVault42CharmGhostAction,
|
||||
)
|
||||
|
||||
__all__ = (
|
||||
|
@ -35,4 +36,5 @@ __all__ = (
|
|||
"TrilioVaultCharm",
|
||||
"TrilioVaultSubordinateCharm",
|
||||
"TrilioVaultCharmGhostAction",
|
||||
"TrilioVault42CharmGhostAction",
|
||||
)
|
||||
|
|
|
@ -598,6 +598,20 @@ class TrilioVaultCharmGhostAction(object):
|
|||
for local_share, ghost_share in share_mappings:
|
||||
self._ghost_nfs_share(local_share, ghost_share)
|
||||
|
||||
def trilio_share_mounted(self, share_path):
|
||||
"""Check if share_path is mounted
|
||||
|
||||
:param local_share: Local NFS share URL
|
||||
:type local_share: str
|
||||
:returns: Whether share is mounted
|
||||
:rtype: bool
|
||||
"""
|
||||
_share_path = os.path.join(
|
||||
TV_MOUNTS,
|
||||
self._encode_endpoint(share_path))
|
||||
current_mounts = [mount[0] for mount in ch_core.host.mounts()]
|
||||
return _share_path in current_mounts
|
||||
|
||||
def _ghost_nfs_share(self, local_share, ghost_share):
|
||||
"""Bind mount a local unit NFS share to another sites location
|
||||
|
||||
|
@ -614,9 +628,7 @@ class TrilioVaultCharmGhostAction(object):
|
|||
TV_MOUNTS, self._encode_endpoint(ghost_share)
|
||||
)
|
||||
|
||||
current_mounts = [mount[0] for mount in ch_core.host.mounts()]
|
||||
|
||||
if nfs_share_path not in current_mounts:
|
||||
if not self.trilio_share_mounted(local_share):
|
||||
# Trilio has not mounted the NFS share so return
|
||||
raise NFSShareNotMountedException(
|
||||
"nfs-share ({}) not mounted".format(
|
||||
|
@ -624,7 +636,7 @@ class TrilioVaultCharmGhostAction(object):
|
|||
)
|
||||
)
|
||||
|
||||
if ghost_share_path in current_mounts:
|
||||
if self.trilio_share_mounted(ghost_share):
|
||||
# bind mount already setup so return
|
||||
raise GhostShareAlreadyMountedException(
|
||||
"ghost mountpoint ({}) already bound".format(ghost_share_path)
|
||||
|
@ -634,3 +646,39 @@ class TrilioVaultCharmGhostAction(object):
|
|||
os.mkdir(ghost_share_path)
|
||||
|
||||
ch_core.host.mount(nfs_share_path, ghost_share_path, options="bind")
|
||||
|
||||
|
||||
class TrilioVault42CharmGhostAction(TrilioVaultCharmGhostAction):
|
||||
|
||||
def _encode_endpoint_uri(self, backup_endpoint):
|
||||
"""base64 encode a backup uri for cross mounting support"""
|
||||
return base64.b64encode(backup_endpoint.encode()).decode()
|
||||
|
||||
def _encode_endpoint_path(self, backup_endpoint):
|
||||
"""base64 encode an backup path for cross mounting support"""
|
||||
return base64.b64encode(
|
||||
str.encode(urlparse(backup_endpoint).path)).decode()
|
||||
|
||||
def _encode_endpoint(self, backup_endpoint):
|
||||
"""base64 encode an backup endpoint for cross mounting support"""
|
||||
return self._encode_endpoint_path(backup_endpoint)
|
||||
|
||||
def trilio_share_mounted(self, share_path):
|
||||
"""Check if share_path is mounted
|
||||
|
||||
:param local_share: Local NFS share URL
|
||||
:type local_share: str
|
||||
:returns: Whether share is mounted
|
||||
:rtype: bool
|
||||
"""
|
||||
mount_paths = [
|
||||
os.path.join(
|
||||
TV_MOUNTS,
|
||||
self._encode_endpoint_path(share_path)
|
||||
),
|
||||
os.path.join(
|
||||
TV_MOUNTS,
|
||||
self._encode_endpoint_uri(share_path)
|
||||
)]
|
||||
current_mounts = [mount[0] for mount in ch_core.host.mounts()]
|
||||
return any(m in current_mounts for m in mount_paths)
|
||||
|
|
|
@ -30,7 +30,7 @@ class TrilioVaultFoobarSubordinate(trilio.TrilioVaultSubordinateCharm):
|
|||
class TestTrilioCharmGhostAction(BaseOpenStackCharmTest):
|
||||
|
||||
_nfs_share = "10.20.30.40:/srv/trilioshare"
|
||||
_ghost_share = "50.20.30.40:/srv/trilioshare"
|
||||
_ghost_share = "50.20.30.40:/srv/trilioghostshare"
|
||||
|
||||
def setUp(self):
|
||||
super().setUp(trilio.TrilioVaultCharmGhostAction, {})
|
||||
|
@ -112,6 +112,91 @@ class TestTrilioCharmGhostAction(BaseOpenStackCharmTest):
|
|||
)
|
||||
|
||||
|
||||
class TestTrilioVault42CharmGhostAction(BaseOpenStackCharmTest):
|
||||
|
||||
_nfs_share = "10.20.30.40:/srv/trilioshare"
|
||||
_ghost_share = "50.20.30.40:/srv/trilioghostshare"
|
||||
|
||||
def setUp(self):
|
||||
super().setUp(trilio.TrilioVaultCharmGhostAction, {})
|
||||
self.patch_object(trilio.ch_core.hookenv, "config")
|
||||
self.patch_object(trilio.ch_core.host, "mounts")
|
||||
self.patch_object(trilio.ch_core.host, "mount")
|
||||
self.patch_object(trilio.os.path, "exists")
|
||||
self.patch_object(trilio.os, "mkdir")
|
||||
|
||||
self.trilio_charm = trilio.TrilioVault42CharmGhostAction()
|
||||
self._nfs_path = os.path.join(
|
||||
trilio.TV_MOUNTS,
|
||||
self.trilio_charm._encode_endpoint(self._nfs_share),
|
||||
)
|
||||
self._ghost_path = os.path.join(
|
||||
trilio.TV_MOUNTS,
|
||||
self.trilio_charm._encode_endpoint(self._ghost_share),
|
||||
)
|
||||
|
||||
def test__ghost_nfs_share(self):
|
||||
self.config.return_value = self._nfs_share
|
||||
self.mounts.return_value = [
|
||||
["/srv/nova", "/dev/sda"],
|
||||
[self._nfs_path, self._nfs_share],
|
||||
]
|
||||
self.exists.return_value = False
|
||||
self.trilio_charm._ghost_nfs_share(self._nfs_share,
|
||||
self._ghost_share)
|
||||
self.exists.assert_called_once_with(self._ghost_path)
|
||||
self.mkdir.assert_called_once_with(self._ghost_path)
|
||||
self.mount.assert_called_once_with(
|
||||
self._nfs_path, self._ghost_path, options="bind"
|
||||
)
|
||||
|
||||
def test__ghost_nfs_share_already_bound(self):
|
||||
self.config.return_value = self._nfs_share
|
||||
self.mounts.return_value = [
|
||||
["/srv/nova", "/dev/sda"],
|
||||
[self._nfs_path, self._nfs_share],
|
||||
[self._ghost_path, self._nfs_share],
|
||||
]
|
||||
with self.assertRaises(trilio.GhostShareAlreadyMountedException):
|
||||
self.trilio_charm._ghost_nfs_share(self._nfs_share,
|
||||
self._ghost_share)
|
||||
self.mount.assert_not_called()
|
||||
|
||||
def test__ghost_nfs_share_nfs_unmounted(self):
|
||||
self.config.return_value = self._nfs_share
|
||||
self.mounts.return_value = [["/srv/nova", "/dev/sda"]]
|
||||
self.exists.return_value = False
|
||||
with self.assertRaises(trilio.NFSShareNotMountedException):
|
||||
self.trilio_charm._ghost_nfs_share(self._nfs_share,
|
||||
self._ghost_share)
|
||||
self.mount.assert_not_called()
|
||||
|
||||
def test_ghost_nfs_share(self):
|
||||
self.patch_object(self.trilio_charm, "_ghost_nfs_share")
|
||||
self.config.return_value = (
|
||||
"10.20.30.40:/srv/trilioshare,10.20.30.40:/srv/trilioshare2"
|
||||
)
|
||||
self.trilio_charm.ghost_nfs_share(
|
||||
"50.20.30.40:/srv/trilioshare,50.20.30.40:/srv/trilioshare2"
|
||||
)
|
||||
self._ghost_nfs_share.assert_has_calls([
|
||||
mock.call("10.20.30.40:/srv/trilioshare",
|
||||
"50.20.30.40:/srv/trilioshare"),
|
||||
mock.call("10.20.30.40:/srv/trilioshare2",
|
||||
"50.20.30.40:/srv/trilioshare2")
|
||||
])
|
||||
|
||||
def test_ghost_nfs_share_mismatch(self):
|
||||
self.patch_object(self.trilio_charm, "_ghost_nfs_share")
|
||||
self.config.return_value = (
|
||||
"10.20.30.40:/srv/trilioshare,10.20.30.40:/srv/trilioshare2"
|
||||
)
|
||||
with self.assertRaises(trilio.MismatchedConfigurationException):
|
||||
self.trilio_charm.ghost_nfs_share(
|
||||
"50.20.30.40:/srv/trilioshare"
|
||||
)
|
||||
|
||||
|
||||
class TestTrilioCommonBehaviours(BaseOpenStackCharmTest):
|
||||
|
||||
def setUp(self):
|
||||
|
|
Loading…
Reference in New Issue