summaryrefslogtreecommitdiffstats
path: root/glustolibs-gluster-gd2/glustolibs/gluster/gluster_base_class.py
blob: 138d5e15d9e8711eef02e64dde9caf3c8090f39c (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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
#  Copyright (C) 2019 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: Module containing GlusterBaseClass which defines all the
        variables necessary for tests.
"""

import unittest
from glusto.core import Glusto as g
from glustolibs.gluster.exceptions import ConfigError, ExecutionError
from glustolibs.gluster.peer_ops import is_peer_connected, peer_status
from glustolibs.io.utils import log_mounts_info
from glustolibs.gluster.lib_utils import (
    get_ip_from_hostname, configure_volumes,
    configure_mounts, inject_msg_in_gluster_logs,
    configure_logs, set_conf_entity)
from glustolibs.gluster.volume_ops import set_volume_options
from glustolibs.gluster.volume_libs import (setup_volume,
                                            cleanup_volume,
                                            log_volume_info_and_status)


class runs_on(g.CarteTestClass):
    """Decorator providing runs_on capability for standard unittest script"""

    def __init__(self, value):
        # the names of the class attributes set by the runs_on decorator
        self.axis_names = ['volume_type', 'mount_type']

        # the options to replace 'ALL' in selections
        self.available_options = [['distributed', 'replicated',
                                   'distributed-replicated'],
                                  ['glusterfs']]

        # these are the volume and mount options to run and set in config
        # what do runs_on_volumes and runs_on_mounts need to be named????
        run_on_volumes = self.available_options[0]
        run_on_mounts = self.available_options[1]
        if g.config.get('gluster', "")['running_on_volumes']:
            run_on_volumes = g.config['gluster']['running_on_volumes']
        if g.config.get('gluster', "")['running_on_mounts']:
            run_on_mounts = g.config['gluster']['running_on_mounts']

        # selections is the above info from the run that is intersected with
        # the limits from the test script
        self.selections = [run_on_volumes, run_on_mounts]

        # value is the limits that are passed in by the decorator
        self.limits = value


class GlusterBaseClass(unittest.TestCase):
    """GlusterBaseClass to be subclassed by Gluster Tests.
    This class reads the config for variable values that will be used in
    gluster tests. If variable values are not specified in the config file,
    the variable are defaulted to specific values.
    """

    volume_type = None
    mount_type = None

    @classmethod
    def validate_peers_are_connected(cls):
        """Validate whether each server in the cluster is connected to
        all other servers in cluster.
        Returns (bool): True if all peers are in connected with other peers.
            False otherwise.
        """
        # Validate if peer is connected from all the servers
        g.log.info("Validating if servers %s are connected from other servers "
                   "in the cluster", cls.servers)
        for server in cls.servers:
            g.log.info("Validate servers %s are in connected from  node %s",
                       cls.servers, server)
            ret = is_peer_connected(server, cls.servers)
            if not ret:
                g.log.error("Some or all servers %s are not in connected "
                            "state from node %s", cls.servers, server)
                return False
            g.log.info("Successfully validated servers %s are all in "
                       "connected state from node %s",
                       cls.servers, server)
        g.log.info("Successfully validated all servers %s are in connected "
                   "state from other servers in the cluster", cls.servers)

        # Peer Status from mnode
        peer_status(cls.mnode)

        return True

    @classmethod
    def setup_volume(cls, volume_create_force=False):
        """Setup the volume:
            - Create the volume, Start volume, Set volume
            options, enable snapshot/quota/tier if specified in the config
            file.
            - Wait for volume processes to be online
            - Export volume as NFS/SMB share if mount_type is NFS or SMB
            - Log volume info and status
        Args:
            volume_create_force(bool): True if create_volume should be
                executed with 'force' option.
        Returns (bool): True if all the steps mentioned in the descriptions
            passes. False otherwise.
        """
        force_volume_create = False
        if cls.volume_create_force:
            force_volume_create = True

        # Validate peers before setting up volume
        g.log.info("Validate peers before setting up volume ")
        ret = cls.validate_peers_are_connected()
        if not ret:
            g.log.error("Failed to validate peers are in connected state "
                        "before setting up volume")
            return False
        g.log.info("Successfully validated peers are in connected state "
                   "before setting up volume")

        # Setup Volume
        g.log.info("Setting up volume %s", cls.volname)
        ret = setup_volume(mnode=cls.mnode,
                           all_servers_info=cls.all_servers_info,
                           volume_config=cls.volume, force=force_volume_create)
        if not ret:
            g.log.error("Failed to Setup volume %s", cls.volname)
            return False
        g.log.info("Successful in setting up volume %s", cls.volname)

        # ToDo : Wait for volume processes to be online

        # Log Volume Info and Status
        g.log.info("Log Volume %s Info and Status", cls.volname)
        ret = log_volume_info_and_status(cls.mnode, cls.volname)
        if not ret:
            g.log.error("Logging volume %s info and status failed",
                        cls.volname)
            return False
        g.log.info("Successful in logging volume %s info and status",
                   cls.volname)

        return True

    @classmethod
    def mount_volume(cls, mounts):
        """Mount volume
        Args:
            mounts(list): List of mount_objs
        Returns (bool): True if mounting the volume for a mount obj is
            successful. False otherwise
        """
        g.log.info("Starting to mount volume %s", cls.volname)
        for mount_obj in mounts:
            g.log.info("Mounting volume '%s:%s' on '%s:%s'",
                       mount_obj.server_system, mount_obj.volname,
                       mount_obj.client_system, mount_obj.mountpoint)
            ret = mount_obj.mount()
            if not ret:
                g.log.error("Failed to mount volume '%s:%s' on '%s:%s'",
                            mount_obj.server_system, mount_obj.volname,
                            mount_obj.client_system, mount_obj.mountpoint)
                return False
            else:
                g.log.info("Successful in mounting volume '%s:%s' on "
                           "'%s:%s'", mount_obj.server_system,
                           mount_obj.volname, mount_obj.client_system,
                           mount_obj.mountpoint)
        g.log.info("Successful in mounting all mount objs for the volume %s",
                   cls.volname)

        # Get mounts info
        g.log.info("Get mounts Info:")
        log_mounts_info(mounts)

        return True

    @classmethod
    def setup_volume_and_mount_volume(cls, mounts, volume_create_force=False):
        """Setup the volume and mount the volume
        Args:
            mounts(list): List of mount_objs
            volume_create_force(bool): True if create_volume should be
                executed with 'force' option.
        Returns (bool): True if setting up volume and mounting the volume
            for a mount obj is successful. False otherwise
        """
        # Setup Volume
        _rc = cls.setup_volume(volume_create_force)
        if not _rc:
            return _rc

        # Mount Volume
        _rc = cls.mount_volume(mounts)
        if not _rc:
            return _rc

        return True

    @classmethod
    def unmount_volume(cls, mounts):
        """Unmount all mounts for the volume
        Args:
            mounts(list): List of mount_objs
        Returns (bool): True if unmounting the volume for a mount obj is
            successful. False otherwise
        """
        # Unmount volume
        g.log.info("Starting to UnMount Volume %s", cls.volname)
        for mount_obj in mounts:
            g.log.info("UnMounting volume '%s:%s' on '%s:%s'",
                       mount_obj.server_system, mount_obj.volname,
                       mount_obj.client_system, mount_obj.mountpoint)
            ret = mount_obj.unmount()
            if not ret:
                g.log.error("Failed to unmount volume '%s:%s' on '%s:%s'",
                            mount_obj.server_system, mount_obj.volname,
                            mount_obj.client_system, mount_obj.mountpoint)

                # Get mounts info
                g.log.info("Get mounts Info:")
                log_mounts_info(cls.mounts)

                return False
            else:
                g.log.info("Successful in unmounting volume '%s:%s' on "
                           "'%s:%s'", mount_obj.server_system,
                           mount_obj.volname, mount_obj.client_system,
                           mount_obj.mountpoint)
        g.log.info("Successful in unmounting all mount objs for the volume %s",
                   cls.volname)

        # Get mounts info
        g.log.info("Get mounts Info:")
        log_mounts_info(mounts)

        return True

    @classmethod
    def cleanup_volume(cls):
        """Cleanup the volume
        Returns (bool): True if cleanup volume is successful. False otherwise.
        """
        g.log.info("Cleanup Volume %s", cls.volname)
        ret = cleanup_volume(mnode=cls.mnode, volname=cls.volname)
        if not ret:
            g.log.error("cleanup of volume %s failed", cls.volname)
        else:
            g.log.info("Successfully cleaned-up volume %s", cls.volname)

        # Log Volume Info and Status
        g.log.info("Log Volume %s Info and Status", cls.volname)
        log_volume_info_and_status(cls.mnode, cls.volname)

        return ret

    @classmethod
    def unmount_volume_and_cleanup_volume(cls, mounts):
        """Unmount the volume and cleanup volume
        Args:
            mounts(list): List of mount_objs
        Returns (bool): True if unmounting the volume for the mounts and
            cleaning up volume is successful. False otherwise
        """
        # UnMount Volume
        _rc = cls.unmount_volume(mounts)
        if not _rc:
            return _rc

        # Setup Volume
        _rc = cls.cleanup_volume()
        if not _rc:
            return _rc
        return True

    @classmethod
    def setUpClass(cls):
        """Initialize all the variables necessary for testing Gluster
        """
        # Set the values of servers, clients, servers_info and clients_info
        cls.servers = set_conf_entity('servers')
        cls.clients = set_conf_entity('clients')
        cls.all_servers_info = set_conf_entity('servers_info')
        cls.all_clients_info = set_conf_entity('clients_info')

        # Set mnode : Node on which gluster commands are executed
        cls.mnode = cls.servers[0]

        # Server IP's
        cls.servers_ips = []
        cls.servers_ips = get_ip_from_hostname(cls.servers)

        # Get the volume configuration
        (cls.default_volume_type_config, cls.volume_create_force,
         cls.volume, cls.voltype, cls.volname, cls.mnode) = configure_volumes(
             cls.servers, cls.volume_type)

        # Get the mount configuration.
        cls.clients, cls.mounts_dict_list, cls.mounts = configure_mounts(
            cls.mnode, cls.volname, cls.mount_type, cls.all_clients_info)

        # Get gluster Logs info
        (cls.server_gluster_logs_dirs, cls.server_gluster_logs_files,
         cls.client_gluster_logs_dirs, cls.client_gluster_logs_files,
         cls.glustotest_run_id) = configure_logs()

        msg = "Setupclass: %s : %s" % (cls.__name__, cls.glustotest_run_id)
        g.log.info(msg)
        inject_msg_in_gluster_logs(
            msg, cls.servers, cls.clients,
            cls.mount_type, cls.server_gluster_logs_dirs,
            cls.server_gluster_logs_files,
            cls.client_gluster_logs_dirs,
            cls.client_gluster_logs_dirs)

        # Log the baseclass variables for debugging purposes
        g.log.debug("GlusterBaseClass Variables:\n %s", cls.__dict__)

    def setUp(self):
        msg = "Starting Test : %s : %s" % (self.id(), self.glustotest_run_id)
        g.log.info(msg)
        inject_msg_in_gluster_logs(
            msg, self.servers, self.clients,
            self.mount_type, self.server_gluster_logs_dirs,
            self.server_gluster_logs_files,
            self.client_gluster_logs_dirs,
            self.client_gluster_logs_dirs)

    def tearDown(self):
        msg = "Ending Test: %s : %s" % (self.id(), self.glustotest_run_id)
        g.log.info(msg)
        inject_msg_in_gluster_logs(
            msg, self.servers, self.clients,
            self.mount_type, self.server_gluster_logs_dirs,
            self.server_gluster_logs_files,
            self.client_gluster_logs_dirs,
            self.client_gluster_logs_dirs)

    @classmethod
    def tearDownClass(cls):
        msg = "Teardownclass: %s : %s" % (cls.__name__, cls.glustotest_run_id)
        g.log.info(msg)
        inject_msg_in_gluster_logs(
            msg, cls.servers, cls.clients,
            cls.mount_type, cls.server_gluster_logs_dirs,
            cls.server_gluster_logs_files,
            cls.client_gluster_logs_dirs,
            cls.client_gluster_logs_dirs)