summaryrefslogtreecommitdiffstats
path: root/tests/functional/dht/test_directory_healing.py
blob: e01a0240f637db20a2aed4de0a6a700953b6dc38 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#  Copyright (C) 2018-2020 Red Hat, Inc. <http://www.redhat.com>
#
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License along
#  with this program; if not, write to the Free Software Foundation, Inc.,
#  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
"""
Description:
    Test cases in this module tests directory healing
"""

from glusto.core import Glusto as g
from glustolibs.gluster.exceptions import ExecutionError
from glustolibs.gluster.gluster_base_class import GlusterBaseClass, runs_on
from glustolibs.gluster.brick_libs import (bring_bricks_offline,
                                           bring_bricks_online, get_all_bricks)
from glustolibs.gluster.brickdir import check_hashrange
from glustolibs.gluster.glusterfile import get_file_stat, calculate_hash


@runs_on([['distributed', 'distributed-replicated',
           'distributed-dispersed', 'distributed-arbiter'],
          ['glusterfs', 'nfs']])
class TestDirHeal(GlusterBaseClass):
    '''
    test case: (directory healing)
    - bring down a subvol
    - create a directory so that it does not hash to down subvol
    - bring up the subvol
    - Check if directory is healed
    '''
    # Create Volume and mount according to config file
    def setUp(self):
        """
        Setup and mount volume or raise ExecutionError
        """
        self.get_super_method(self, 'setUp')()

        # Setup Volume
        ret = self.setup_volume_and_mount_volume(self.mounts)
        if not ret:
            g.log.error("Failed to Setup and Mount Volume")
            raise ExecutionError("Failed to Setup and Mount Volume")

    def test_directory_heal(self):
        '''
        Test directory healing.
        '''
        # pylint: disable=too-many-locals
        # pylint: disable=too-many-statements
        # pylint: disable=protected-access

        mount_obj = self.mounts[0]
        mountpoint = mount_obj.mountpoint

        # directory that needs to be created
        parent_dir = mountpoint + '/parent'
        target_dir = mountpoint + '/parent/child'

        # create parent dir
        ret, _, err = g.run(self.clients[0], ("mkdir %s" % parent_dir))
        g.log.info("mkdir of parent directory %s successful", parent_dir)
        self.assertEqual(ret, 0, ('mkdir failed for %s err: %s', parent_dir,
                                  err))
        g.log.info("mkdir of parent successful")

        # find non-hashed subvol for child
        hashed, non_hashed = [], []
        hash_num = calculate_hash(self.mnode, "child")
        bricklist = get_all_bricks(self.mnode, self.volname)
        for brick in bricklist:
            ret = check_hashrange(brick + "/parent")
            hash_range_low = ret[0]
            hash_range_high = ret[1]
            if hash_range_low <= hash_num <= hash_range_high:
                hashed.append(brick)

        non_hashed = [brick for brick in bricklist if brick not in hashed]
        g.log.info("Non-hashed bricks are: %s", non_hashed)

        # bring non_hashed offline
        for brick in non_hashed:
            ret = bring_bricks_offline(self.volname, brick)
            self.assertTrue(ret, ('Error in bringing down brick %s',
                                  brick))
            g.log.info('Non-hashed brick %s is offline', brick)

        # create child directory
        runc = ("mkdir %s" % target_dir)
        ret, _, _ = g.run(self.clients[0], runc)
        self.assertEqual(ret, 0, ('failed to create dir %s' % target_dir))
        g.log.info('mkdir successful %s', target_dir)

        # Check that the dir is not created on the down brick
        for brick in non_hashed:
            non_hashed_host, dir_path = brick.split(":")
            brickpath = ("%s/parent/child" % dir_path)
            ret, _, _ = g.run(non_hashed_host, ("stat %s" % brickpath))
            self.assertEqual(ret, 1, ("Expected %s to be not present on %s" %
                                      (brickpath, non_hashed_host)))
            g.log.info("Stat of %s failed as expected", brickpath)

        # bring up the subvol
        ret = bring_bricks_online(
            self.mnode, self.volname, non_hashed,
            bring_bricks_online_methods='volume_start_force')
        self.assertTrue(ret, "Error in bringing back subvol online")
        g.log.info("Subvol is back online")

        runc = ("ls %s" % target_dir)
        ret, _, _ = g.run(self.clients[0], runc)
        self.assertEqual(ret, 0, ("Lookup on %s failed", target_dir))
        g.log.info("Lookup is successful on %s", target_dir)

        # check if the directory is created on non_hashed
        for brick in non_hashed:
            non_hashed_host, dir_path = brick.split(":")
            absolutedirpath = ("%s/parent/child" % dir_path)
            ret = get_file_stat(non_hashed_host, absolutedirpath)
            self.assertIsNotNone(ret, "Directory is not present on non_hashed")
            g.log.info("Directory is created on non_hashed subvol")

        # check if directory is healed => i.e. layout is zeroed out
        for brick in non_hashed:
            brick_path = ("%s/parent/child" % brick)
            ret = check_hashrange(brick_path)
            hash_range_low = ret[0]
            hash_range_high = ret[1]
            if not hash_range_low and not hash_range_high:
                g.log.info("Directory healing successful")
            else:
                g.log.error("Directory is not healed")

    def tearDown(self):

        # Unmount and cleanup original volume
        g.log.info("Starting to Unmount Volume and Cleanup Volume")
        ret = self.unmount_volume_and_cleanup_volume(mounts=self.mounts)
        if not ret:
            raise ExecutionError("Failed to umount the vol & cleanup Volume")
        g.log.info("Successful in umounting the volume and Cleanup")

        # Calling GlusterBaseClass tearDown
        self.get_super_method(self, 'tearDown')()