summaryrefslogtreecommitdiffstats
path: root/glustolibs-gluster-gd2/glustolibs/gluster/lib_utils.py
blob: ebcdd9d84093903ee7b8bf5520d6e65488b65397 (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
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
#  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: Helper library for gluster modules.
"""

import os
import random
import copy
import datetime
import socket
from uuid import UUID
from glusto.core import Glusto as g
from glustolibs.gluster.mount_ops import create_mount_objs
from glustolibs.gluster.expections import (
        ConfigError, GlusterApiInvalidInputs)


def validate_uuid(brick_id, version=4):
    """
    Validates the uuid
    Args:
       brick_id (str) : Brick_id to be validated
       version (int)
    Returns:
       True (bool) on if the uuid is valid hex code,
       else false
    """
    try:
        UUID(brick_id, version=version)
    except ValueError:
        # If it's a value error, then the string
        # is not a valid hex code for a UUID.
        g.log.error("Invalid brick_id %s", brick_id)
        return False
    return True


def validate_peer_id(peerid):
    """
    Validates the peer id
    Args:
        peer id (str) : peer id to be validated
    Returns:
        Exceptions on failure
    """
    if not validate_uuid(peerid):
        g.log.error("Invalid peer id %s speceified", peerid)
        raise GlusterApiInvalidInputs("Invalid peer id specified")


def inject_msg_in_logs(nodes, log_msg, list_of_dirs=None, list_of_files=None):
    """Injects the message to all log files under all dirs specified on nodes.
    Args:
        nodes (str|list): A server|List of nodes on which message has to be
            injected to logs
        log_msg (str): Message to be injected
        list_of_dirs (list): List of dirs to inject message on log files.
        list_of_files (list): List of files to inject message.
    Returns:
        bool: True if successfully injected msg on all log files.
    """
    if isinstance(nodes, str):
        nodes = [nodes]

    if list_of_dirs is None:
        list_of_dirs = ""

    if isinstance(list_of_dirs, list):
        list_of_dirs = ' '.join(list_of_dirs)

    if list_of_files is None:
        list_of_files = ''

    if isinstance(list_of_files, list):
        list_of_files = ' '.join(list_of_files)

    inject_msg_on_dirs = ""
    inject_msg_on_files = ""
    if list_of_dirs:
        inject_msg_on_dirs = (
            "for dir in %s ; do "
            "for file in `find ${dir} -type f -name '*.log'`; do "
            "echo \"%s\" >> ${file} ; done ;"
            "done; " % (list_of_dirs, log_msg))
    if list_of_files:
        inject_msg_on_files = ("for file in %s ; do "
                               "echo \"%s\" >> ${file} ; done; " %
                               (list_of_files, log_msg))

    cmd = inject_msg_on_dirs + inject_msg_on_files

    results = g.run_parallel(nodes, cmd)

    _rc = True
    # Check for return status
    for host in results:
        ret, _, _ = results[host]
        if ret != 0:
            g.log.error("Failed to inject log message '%s' in dirs '%s', "
                        "in files '%s',  on node'%s'",
                        log_msg, list_of_dirs, list_of_files, host)
            _rc = False
    return _rc


def inject_msg_in_gluster_logs(msg, servers, clients,
                               mount_type,
                               server_gluster_logs_dirs,
                               server_gluster_logs_files,
                               client_gluster_logs_dirs,
                               client_gluster_logs_files):

    """Inject all the gluster logs on servers, clients with msg
    Args:
        msg (str): Message string to be injected
    Returns:
        bool: True if injecting msg on the log files/dirs is successful.
              False Otherwise.
    """
    _rc = True
    # Inject msg on server gluster logs
    ret = inject_msg_in_logs(servers, log_msg=msg,
                             list_of_dirs=server_gluster_logs_dirs)
    if not ret:
        _rc = False

    if mount_type is not None and "glusterfs" in mount_type:
        ret = inject_msg_in_logs(clients, log_msg=msg,
                                 list_of_dirs=client_gluster_logs_dirs,
                                 list_of_files=client_gluster_logs_files)
        if not ret:
            _rc = False
    return _rc


def get_ip_from_hostname(nodes):
    """Returns list of IP's for the list of nodes in order.
    Args:
        nodes(list|str): List of nodes hostnames
    Returns:
        list: List of IP's corresponding to the hostnames of nodes.
    """
    nodes_ips = []
    nodes = to_list(nodes)
    for node in nodes:
        try:
            ip = socket.gethostbyname(node)
        except socket.gaierror as e:
            g.log.error("Failed to get the IP of Host: %s : %s", node,
                        e.strerror)
            ip = None
        nodes_ips.append(ip)
    return nodes_ips


def set_conf_entity(entity_name):
    """Set the value of the entity
    Args:
        entity_name (str) : Value of entity to be set
    Returns:
        Value of the entity
    """
    entity = g.config.get(entity_name)
    if not entity:
        raise ConfigError("'%s' not defined in the global config" % entity_name)
    return entity


def configure_volumes(servers, volume_type):
    """Defines the volume configurations.
    Args:
        servers(list) : List of servers
        volume_type(str) : Type of volume which will be created
    Returns:
        default_volume_type_config(dict) : Volume type configuration
        volume_create_force(bool) : Volume with force option
        volume(dict): Volume configuration
        volname(str): Volume name
        voltype(str): Volume type
    """
    # Defining default volume_types configuration.
    default_volume_type_config = {
        'distributed': {
            'type': 'distributed',
            'dist_count': 4,
            'transport': 'tcp'
            },
        'replicated': {
            'type': 'replicated',
            'replica_count': 2,
            'arbiter_count': 1,
            'transport': 'tcp'
            },
        'distributed-replicated': {
            'type': 'distributed-replicated',
            'dist_count': 2,
            'replica_count': 3,
            'transport': 'tcp'
            }
        }

    # Check if default volume_type configuration is provided in
    # config yml
    if g.config.get('gluster')['volume_types']:
        default_volume_type_from_config = (g.config['gluster']['volume_types'])

        for vol_type in default_volume_type_from_config.keys():
            if default_volume_type_from_config[vol_type]:
                if vol_type in default_volume_type_config:
                    default_volume_type_config[volume_type] = (
                            default_volume_type_from_config[vol_type])

    # Create Volume with force option
    volume_create_force = False
    if g.config.get('gluster')['volume_create_force']:
        volume_create_force = (g.config['gluster']['volume_create_force'])

    # Get the volume configuration.
    volume = {}
    if volume_type:
        found_volume = False
        if g.config.get('gluster')['volumes']:
            for volume in g.config['gluster']['volumes']:
                if volume['voltype']['type'] == volume_type:
                    volume = copy.deepcopy(volume)
                    found_volume = True
                    break

        if found_volume:
            if 'name' not in volume:
                volume['name'] = 'testvol_%s' % volume_type

            if 'servers' not in volume:
                volume['servers'] = servers

        if not found_volume:
            try:
                if g.config['gluster']['volume_types'][volume_type]:
                    volume['voltype'] = (g.config['gluster']['volume_types'][volume_type])
            except KeyError:
                try:
                    volume['voltype'] = (default_volume_type_config
                                         [volume_type])
                except KeyError:
                    raise ConfigError("Unable to get configs of volume "
                                      "type: %s", volume_type)
            volume['name'] = 'testvol_%s' % volume_type
            volume['servers'] = servers

        # Define Volume Useful Variables.
        volname = volume['name']
        voltype = volume['voltype']['type']
        servers = volume['servers']
        mnode = servers[0]
    return (default_volume_type_config, volume_create_force,
            volume, voltype, volname, mnode)


def configure_mounts(mnode, volname, mount_type, all_clients_info):
    """Defines the mount configurations.
    Args:
        mnode(str): Node on which volume should be mounted
        volname(str): Name of the volume
        mount_type(list): Defines the mount type
        all_clients_info(dict): Dict of clients information
    Returns:
        mounts_dict_list(list): List of the mount informations
        mounts(str) : GlusterMount instance
    """
    # Get the mount configuration
    mounts = []
    if mount_type:
        mounts_dict_list = []
        found_mount = False
        if g.config.get('gluster')['mounts']:
            for mount in g.config['gluster']['mounts']:
                if mount['protocol'] == mount_type:
                    temp_mount = {}
                    temp_mount['protocol'] = mount_type
                    if 'volname' in mount and mount['volname']:
                        if mount['volname'] == volname:
                            temp_mount = copy.deepcopy(mount)
                        else:
                            continue
                    else:
                        temp_mount['volname'] = volname
                    if ('server' not in mount or
                            (not mount['server'])):
                        temp_mount['server'] = mnode
                    else:
                        temp_mount['server'] = mount['server']
                    if ('mountpoint' not in mount or
                            (not mount['mountpoint'])):
                        temp_mount['mountpoint'] = (os.path.join(
                            "/mnt", '_'.join([volname,
                                              mount_type])))
                    else:
                        temp_mount['mountpoint'] = mount['mountpoint']
                    if ('client' not in mount or
                            (not mount['client'])):
                        temp_mount['client'] = (
                            all_clients_info[
                                random.choice(
                                        all_clients_info.keys())]
                            )
                    else:
                        temp_mount['client'] = mount['client']
                    if 'options' in mount and mount['options']:
                        temp_mount['options'] = mount['options']
                    else:
                        temp_mount['options'] = ''
                    mounts_dict_list.append(temp_mount)
                    found_mount = True

        if not found_mount:
            for client in all_clients_info.keys():
                mount = {
                        'protocol': mount_type,
                         'server': mnode,
                         'volname': volname,
                         'client': all_clients_info[client],
                         'mountpoint': (os.path.join(
                            "/mnt", '_'.join([volname, mount_type]))),
                         'options': ''
                        }
                mounts_dict_list.append(mount)
        mounts = create_mount_objs(mounts_dict_list)

        # Defining clients from mounts.
        clients = []
        for mount in mounts_dict_list:
            clients.append(mount['client']['host'])
        clients = list(set(clients))

        return clients, mounts_dict_list, mounts


def configure_logs():
    """Defines the gluster log information.
    Returns:
        server_gluster_logs_dirs(list) : List of server logs dirs
        server_gluster_logs_files(list) : List of server logs files
        client_gluster_logs_dirs(list) : List of client logs dirs
        client_gluster_logs_files(list) : List of client logs files
        glustotest_run_id(str) : Time the test run
    """
    # Gluster Logs info
    server_gluster_logs_dirs = ["/var/log/glusterd2/glusterd2.log"]
    server_gluster_logs_files = []
    if g.config.get("gluster")['server_gluster_logs_info']['dirs']:
        server_gluster_logs_dirs = (
                 g.config['gluster']['server_gluster_logs_info']['dirs'])

    if g.config.get("gluster")['server_gluster_logs_info']['files']:
        server_gluster_logs_files = (
                g.config['gluster']['server_gluster_logs_info']['files'])

    client_gluster_logs_dirs = ["/var/log/glusterd2/glusterd2.log"]
    client_gluster_logs_files = ["/var/log/glusterd2/glusterd2.log"]
    if g.config.get("gluster")['client_gluster_logs_info']['dirs']:
        client_gluster_logs_dirs = (
                g.config['gluster']['client_gluster_logs_info']['dirs'])

    if g.config.get("gluster")['client_gluster_logs_info']['files']:
        client_gluster_logs_files = (
                g.config['gluster']['client_gluster_logs_info']['files'])

    # Have a unique string to recognize the test run for logging in
    # gluster logs
    if 'glustotest_run_id' not in g.config:
        g.config['glustotest_run_id'] = (
            datetime.datetime.now().strftime('%H_%M_%d_%m_%Y'))
    glustotest_run_id = g.config['glustotest_run_id']
    g.log.info("Glusto test run id %s", glustotest_run_id)
    return (server_gluster_logs_dirs, server_gluster_logs_files,
            client_gluster_logs_dirs, client_gluster_logs_files,
            glustotest_run_id)