Completed
Pull Request — master (#2731)
by Manas
06:32
created

DatastoreService.set_value()   A

Complexity

Conditions 3

Size

Total Lines 48

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
c 1
b 0
f 0
dl 0
loc 48
rs 9.125
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
from st2common.constants.keyvalue import DATASTORE_KEY_SEPARATOR, SYSTEM_SCOPE
21
22
23
class DatastoreService(object):
24
    """
25
    Class provides public methods for accessing datastore items.
26
    """
27
28
    DATASTORE_NAME_SEPARATOR = DATASTORE_KEY_SEPARATOR
29
30
    def __init__(self, logger, pack_name, class_name, api_username):
31
        self._api_username = api_username
32
        self._pack_name = pack_name
33
        self._class_name = class_name
34
        self._logger = logger
35
36
        self._client = None
37
38
    ##################################
39
    # Methods for datastore management
40
    ##################################
41
42
    def list_values(self, local=True, prefix=None):
43
        """
44
        Retrieve all the datastores items.
45
46
        :param local: List values from a namespace local to this pack/class. Defaults to True.
47
        :type: local: ``bool``
48
49
        :param prefix: Optional key name prefix / startswith filter.
50
        :type prefix: ``str``
51
52
        :rtype: ``list`` of :class:`KeyValuePair`
53
        """
54
        client = self._get_api_client()
55
        self._logger.audit('Retrieving all the value from the datastore')
56
57
        key_prefix = self._get_full_key_prefix(local=local, prefix=prefix)
58
        kvps = client.keys.get_all(prefix=key_prefix)
59
        return kvps
60
61
    def get_value(self, name, local=True, scope=SYSTEM_SCOPE, decrypt=False):
62
        """
63
        Retrieve a value from the datastore for the provided key.
64
65
        By default, value is retrieved from the namespace local to the pack/class. If you want to
66
        retrieve a global value from a datastore, pass local=False to this method.
67
68
        :param name: Key name.
69
        :type name: ``str``
70
71
        :param local: Retrieve value from a namespace local to the pack/class. Defaults to True.
72
        :type: local: ``bool``
73
74
        :param scope: Scope under which item is saved. Defaults to system scope.
75
        :type: local: ``str``
76
77
        :param encrypt: Return the decrypted value. Defaults to False.
78
        :type: local: ``bool``
79
80
        :rtype: ``str`` or ``None``
81
        """
82
        name = self._get_full_key_name(name=name, local=local)
83
84
        client = self._get_api_client()
85
        self._logger.audit('Retrieving value from the datastore (name=%s)', name)
86
87
        try:
88
            params = {'decrypt': str(decrypt).lower(), 'scope': scope}
89
            kvp = client.keys.get_by_id(id=name, params=params)
90
        except Exception:
91
            return None
92
93
        if kvp:
94
            return kvp.value
95
96
        return None
97
98
    def set_value(self, name, value, ttl=None, local=True, scope=SYSTEM_SCOPE, encrypt=False):
99
        """
100
        Set a value for the provided key.
101
102
        By default, value is set in a namespace local to the pack/class. If you want to
103
        set a global value, pass local=False to this method.
104
105
        :param name: Key name.
106
        :type name: ``str``
107
108
        :param value: Key value.
109
        :type value: ``str``
110
111
        :param ttl: Optional TTL (in seconds).
112
        :type ttl: ``int``
113
114
        :param local: Set value in a namespace local to the pack/class. Defaults to True.
115
        :type: local: ``bool``
116
117
        :param scope: Scope under which to place the item. Defaults to system scope.
118
        :type: local: ``str``
119
120
        :param encrypt: Encrypyt the value when saving. Defaults to False.
121
        :type: local: ``bool``
122
123
        :return: ``True`` on success, ``False`` otherwise.
124
        :rtype: ``bool``
125
        """
126
        name = self._get_full_key_name(name=name, local=local)
127
128
        value = str(value)
129
        client = self._get_api_client()
130
131
        self._logger.audit('Setting value in the datastore (name=%s)', name)
132
133
        instance = KeyValuePair()
134
        instance.id = name
135
        instance.name = name
136
        instance.value = value
137
        instance.scope = scope
138
        if encrypt:
139
            instance.secret = True
140
141
        if ttl:
142
            instance.ttl = ttl
143
144
        client.keys.update(instance=instance)
145
        return True
146
147
    def delete_value(self, name, local=True, scope=SYSTEM_SCOPE):
148
        """
149
        Delete the provided key.
150
151
        By default, value is deleted from a namespace local to the pack/class. If you want to
152
        delete a global value, pass local=False to this method.
153
154
        :param name: Name of the key to delete.
155
        :type name: ``str``
156
157
        :param local: Delete a value in a namespace local to the pack/class. Defaults to True.
158
        :type: local: ``bool``
159
160
        :param scope: Scope under which item is saved. Defaults to system scope.
161
        :type: local: ``str``
162
163
        :return: ``True`` on success, ``False`` otherwise.
164
        :rtype: ``bool``
165
        """
166
        name = self._get_full_key_name(name=name, local=local)
167
168
        client = self._get_api_client()
169
170
        instance = KeyValuePair()
171
        instance.id = name
172
        instance.name = name
173
174
        self._logger.audit('Deleting value from the datastore (name=%s)', name)
175
176
        try:
177
            params = {'scope': scope}
178
            client.keys.delete(instance=instance, params=params)
179
        except Exception:
180
            return False
181
182
        return True
183
184
    def _get_api_client(self):
185
        """
186
        Retrieve API client instance.
187
        """
188
        if not self._client:
189
            ttl = (24 * 60 * 60)
190
            temporary_token = create_token(username=self._api_username, ttl=ttl)
191
            api_url = get_full_public_api_url()
192
            self._client = Client(api_url=api_url, token=temporary_token.token)
193
194
        return self._client
195
196
    def _get_full_key_name(self, name, local):
197
        """
198
        Retrieve a full key name.
199
200
        :rtype: ``str``
201
        """
202
        if local:
203
            name = self._get_key_name_with_prefix(name=name)
204
205
        return name
206
207
    def _get_full_key_prefix(self, local, prefix=None):
208
        if local:
209
            key_prefix = self._get_local_key_name_prefix()
210
211
            if prefix:
212
                key_prefix += prefix
213
        else:
214
            key_prefix = prefix
215
216
        return key_prefix
217
218
    def _get_local_key_name_prefix(self):
219
        """
220
        Retrieve key prefix which is local to this pack/class.
221
        """
222
        key_prefix = self._get_datastore_key_prefix() + self.DATASTORE_NAME_SEPARATOR
223
        return key_prefix
224
225
    def _get_key_name_with_prefix(self, name):
226
        """
227
        Retrieve a full key name which is local to the current pack/class.
228
229
        :param name: Base datastore key name.
230
        :type name: ``str``
231
232
        :rtype: ``str``
233
        """
234
        prefix = self._get_datastore_key_prefix()
235
        full_name = prefix + self.DATASTORE_NAME_SEPARATOR + name
236
        return full_name
237
238
    def _get_datastore_key_prefix(self):
239
        prefix = '%s.%s' % (self._pack_name, self._class_name)
240
        return prefix
241