Completed
Push — master ( dfd3a9...2b76ca )
by Manas
05:54
created

st2common.services.DatastoreService   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 198
Duplicated Lines 0 %
Metric Value
wmc 19
dl 0
loc 198
rs 10

11 Methods

Rating   Name   Duplication   Size   Complexity  
A __init__() 0 7 1
A _get_key_name_with_prefix() 0 12 1
B delete_value() 0 32 2
A _get_full_key_name() 0 10 2
A _get_full_key_prefix() 0 10 3
A _get_local_key_name_prefix() 0 6 1
A _get_api_client() 0 11 2
A _get_datastore_key_prefix() 0 3 1
B get_value() 0 29 3
A list_values() 0 18 1
B set_value() 0 39 2
1
# Licensed to the StackStorm, Inc ('StackStorm') under one or more
2
# contributor license agreements.  See the NOTICE file distributed with
3
# this work for additional information regarding copyright ownership.
4
# The ASF licenses this file to You under the Apache License, Version 2.0
5
# (the "License"); you may not use this file except in compliance with
6
# the License.  You may obtain a copy of the License at
7
#
8
#     http://www.apache.org/licenses/LICENSE-2.0
9
#
10
# Unless required by applicable law or agreed to in writing, software
11
# distributed under the License is distributed on an "AS IS" BASIS,
12
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
# See the License for the specific language governing permissions and
14
# limitations under the License.
15
16
from st2client.client import Client
17
from st2client.models import KeyValuePair
18
from st2common.services.access import create_token
19
from st2common.util.api import get_full_public_api_url
20
21
22
class DatastoreService(object):
23
    """
24
    Class provides public methods for accessing datastore items.
25
    """
26
27
    DATASTORE_NAME_SEPARATOR = ':'
28
29
    def __init__(self, logger, pack_name, class_name, api_username):
30
        self._api_username = api_username
31
        self._pack_name = pack_name
32
        self._class_name = class_name
33
        self._logger = logger
34
35
        self._client = None
36
37
    ##################################
38
    # Methods for datastore management
39
    ##################################
40
41
    def list_values(self, local=True, prefix=None):
42
        """
43
        Retrieve all the datastores items.
44
45
        :param local: List values from a namespace local to this pack/class. Defaults to True.
46
        :type: local: ``bool``
47
48
        :param prefix: Optional key name prefix / startswith filter.
49
        :type prefix: ``str``
50
51
        :rtype: ``list`` of :class:`KeyValuePair`
52
        """
53
        client = self._get_api_client()
54
        self._logger.audit('Retrieving all the value from the datastore')
55
56
        key_prefix = self._get_full_key_prefix(local=local, prefix=prefix)
57
        kvps = client.keys.get_all(prefix=key_prefix)
58
        return kvps
59
60
    def get_value(self, name, local=True):
61
        """
62
        Retrieve a value from the datastore for the provided key.
63
64
        By default, value is retrieved from the namespace local to the pack/class. If you want to
65
        retrieve a global value from a datastore, pass local=False to this method.
66
67
        :param name: Key name.
68
        :type name: ``str``
69
70
        :param local: Retrieve value from a namespace local to the pack/class. Defaults to True.
71
        :type: local: ``bool``
72
73
        :rtype: ``str`` or ``None``
74
        """
75
        name = self._get_full_key_name(name=name, local=local)
76
77
        client = self._get_api_client()
78
        self._logger.audit('Retrieving value from the datastore (name=%s)', name)
79
80
        try:
81
            kvp = client.keys.get_by_id(id=name)
82
        except Exception:
83
            return None
84
85
        if kvp:
86
            return kvp.value
87
88
        return None
89
90
    def set_value(self, name, value, ttl=None, local=True):
91
        """
92
        Set a value for the provided key.
93
94
        By default, value is set in a namespace local to the pack/class. If you want to
95
        set a global value, pass local=False to this method.
96
97
        :param name: Key name.
98
        :type name: ``str``
99
100
        :param value: Key value.
101
        :type value: ``str``
102
103
        :param ttl: Optional TTL (in seconds).
104
        :type ttl: ``int``
105
106
        :param local: Set value in a namespace local to the pack/class. Defaults to True.
107
        :type: local: ``bool``
108
109
        :return: ``True`` on success, ``False`` otherwise.
110
        :rtype: ``bool``
111
        """
112
        name = self._get_full_key_name(name=name, local=local)
113
114
        value = str(value)
115
        client = self._get_api_client()
116
117
        self._logger.audit('Setting value in the datastore (name=%s)', name)
118
119
        instance = KeyValuePair()
120
        instance.id = name
121
        instance.name = name
122
        instance.value = value
123
124
        if ttl:
125
            instance.ttl = ttl
126
127
        client.keys.update(instance=instance)
128
        return True
129
130
    def delete_value(self, name, local=True):
131
        """
132
        Delete the provided key.
133
134
        By default, value is deleted from a namespace local to the pack/class. If you want to
135
        delete a global value, pass local=False to this method.
136
137
        :param name: Name of the key to delete.
138
        :type name: ``str``
139
140
        :param local: Delete a value in a namespace local to the pack/class. Defaults to True.
141
        :type: local: ``bool``
142
143
        :return: ``True`` on success, ``False`` otherwise.
144
        :rtype: ``bool``
145
        """
146
        name = self._get_full_key_name(name=name, local=local)
147
148
        client = self._get_api_client()
149
150
        instance = KeyValuePair()
151
        instance.id = name
152
        instance.name = name
153
154
        self._logger.audit('Deleting value from the datastore (name=%s)', name)
155
156
        try:
157
            client.keys.delete(instance=instance)
158
        except Exception:
159
            return False
160
161
        return True
162
163
    def _get_api_client(self):
164
        """
165
        Retrieve API client instance.
166
        """
167
        if not self._client:
168
            ttl = (24 * 60 * 60)
169
            temporary_token = create_token(username=self._api_username, ttl=ttl)
170
            api_url = get_full_public_api_url()
171
            self._client = Client(api_url=api_url, token=temporary_token.token)
172
173
        return self._client
174
175
    def _get_full_key_name(self, name, local):
176
        """
177
        Retrieve a full key name.
178
179
        :rtype: ``str``
180
        """
181
        if local:
182
            name = self._get_key_name_with_prefix(name=name)
183
184
        return name
185
186
    def _get_full_key_prefix(self, local, prefix=None):
187
        if local:
188
            key_prefix = self._get_local_key_name_prefix()
189
190
            if prefix:
191
                key_prefix += prefix
192
        else:
193
            key_prefix = prefix
194
195
        return key_prefix
196
197
    def _get_local_key_name_prefix(self):
198
        """
199
        Retrieve key prefix which is local to this pack/class.
200
        """
201
        key_prefix = self._get_datastore_key_prefix() + self.DATASTORE_NAME_SEPARATOR
202
        return key_prefix
203
204
    def _get_key_name_with_prefix(self, name):
205
        """
206
        Retrieve a full key name which is local to the current pack/class.
207
208
        :param name: Base datastore key name.
209
        :type name: ``str``
210
211
        :rtype: ``str``
212
        """
213
        prefix = self._get_datastore_key_prefix()
214
        full_name = prefix + self.DATASTORE_NAME_SEPARATOR + name
215
        return full_name
216
217
    def _get_datastore_key_prefix(self):
218
        prefix = '%s.%s' % (self._pack_name, self._class_name)
219
        return prefix
220