aboutsummaryrefslogtreecommitdiff
path: root/app/utils/batch/common.py
blob: 0bb8b3d1d6c9fc1ae59b97788d838304e8887489 (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
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import models
import types

import utils.batch.batch_op as batchop
import utils.db


def create_batch_operation(json_obj, db_options):
    """Create a `BatchOperation` object from a JSON object.

    No validity checks are performed on the JSON object, it must be a valid
    batch operation JSON structure.

    :param json_obj: The JSON object with all the necessary paramters.
    :type json_obj: dict
    :param db_options: The mongodb configuration parameters.
    :type db_options: dict
    :return A `BatchOperation` object, or None if the `BatchOperation` cannot
    be constructed.
    """
    batch_op = None

    if json_obj:
        get_func = json_obj.get
        collection = get_func(models.COLLECTION_KEY, None)

        if collection:
            database = utils.db.get_db_connection(db_options)
            operation_id = get_func(models.OP_ID_KEY, None)

            if collection == models.COUNT_COLLECTION:
                batch_op = batchop.BatchCountOperation(
                    collection, database, operation_id=operation_id
                )
            elif collection == models.BOOT_COLLECTION:
                batch_op = batchop.BatchBootOperation(
                    collection, database, operation_id=operation_id
                )
            elif collection == models.JOB_COLLECTION:
                batch_op = batchop.BatchJobOperation(
                    collection, database, operation_id=operation_id
                )
            elif collection == models.DEFCONFIG_COLLECTION:
                batch_op = batchop.BatchDefconfigOperation(
                    collection, database, operation_id=operation_id)
            else:
                batch_op = batchop.BatchOperation(
                    collection, database, operation_id=operation_id)

            batch_op.query_args = get_batch_query_args(
                get_func(models.QUERY_KEY, None)
            )
            batch_op.document_id = get_func(models.DOCUMENT_ID_KEY, None)
            batch_op.query_args_func = batch_op.query_args.get
            batch_op.method = get_func(models.METHOD_KEY, None)

    return batch_op


def execute_batch_operation(json_obj, db_options):
    """Create and execute the batch op as defined in the JSON object.

    :param json_obj: The JSON object that will be used to create the batch
    operation.
    :type json_obj: dict
    :param db_options: The mongodb database connection parameters.
    :type db_options: dict
    :return The result of the operation execution, or None.
    """
    batch_op = create_batch_operation(json_obj, db_options)

    result = None
    if batch_op:
        result = batch_op.run()

    return result


def get_batch_query_args(query):
    """From a query string, retrieve the key-value pairs.

    The query string has to be built as a normal HTTP query: it can either
    start with a question mark or not, key and values must be separated
    by an equal sign (=), and multiple key-value pairs must be separated
    by an ampersand (&):

        [?]key=value[&key=value&key=value...]

    The values are then retrieved and stored in a set to avoid duplicates.

    :param query: The query string to analyze.
    :type query: string
    :return A dictionary with keys the keys from the query, and values the
    values stored in a list.
    """
    args = {}

    if all([query, isinstance(query, types.StringTypes)]):
        if query.startswith("?"):
            query = query[1:]

        query = query.split("&")
        if isinstance(query, types.ListType):
            for arg in query:
                arg = arg.split("=")
                # Can't have query with just one element, they have to be
                # key=value.
                if len(arg) > 1:
                    if args.get(arg[0], None):
                        args[arg[0]].append(arg[1])
                    else:
                        args[arg[0]] = list([arg[1]])
                    args[arg[0]] = list(set(args[arg[0]]))

    return args