Passed
Push — develop ( b7e2c3...d0345b )
by Plexxi
08:11 queued 04:18
created

KeyValuePairGetCommand.__init__()   A

Complexity

Conditions 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 1
dl 0
loc 4
rs 10
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
import os
17
import json
18
import logging
19
from os.path import join as pjoin
20
21
from st2client.commands import resource
22
from st2client.commands.noop import NoopCommand
23
from st2client.commands.resource import add_auth_token_to_kwargs_from_cli
24
from st2client.formatters import table
25
from st2client.models.keyvalue import KeyValuePair
26
from st2client.utils.date import format_isodate_for_user_timezone
27
28
LOG = logging.getLogger(__name__)
29
30
31
class KeyValuePairBranch(resource.ResourceBranch):
32
33
    def __init__(self, description, app, subparsers, parent_parser=None):
34
        super(KeyValuePairBranch, self).__init__(
35
            KeyValuePair, description, app, subparsers,
36
            parent_parser=parent_parser,
37
            commands={
38
                'list': KeyValuePairListCommand,
39
                'get': KeyValuePairGetCommand,
40
                'delete': KeyValuePairDeleteCommand,
41
                'create': NoopCommand,
42
                'update': NoopCommand
43
            })
44
45
        # Registers extended commands
46
        self.commands['set'] = KeyValuePairSetCommand(self.resource, self.app,
47
                                                      self.subparsers)
48
        self.commands['load'] = KeyValuePairLoadCommand(
49
            self.resource, self.app, self.subparsers)
50
        self.commands['delete_by_prefix'] = KeyValuePairDeleteByPrefixCommand(
51
            self.resource, self.app, self.subparsers)
52
53
        # Remove unsupported commands
54
        # TODO: Refactor parent class and make it nicer
55
        del self.commands['create']
56
        del self.commands['update']
57
58
59
class KeyValuePairListCommand(resource.ResourceListCommand):
60
    display_attributes = ['name', 'value', 'secret', 'encrypted', 'expire_timestamp']
61
    attribute_transform_functions = {
62
        'expire_timestamp': format_isodate_for_user_timezone,
63
    }
64
65
    def __init__(self, *args, **kwargs):
66
        super(KeyValuePairListCommand, self).__init__(*args, **kwargs)
67
68
        # Filter options
69
        self.parser.add_argument('--prefix', help=('Only return values which name starts with the '
70
                                                   ' provided prefix.'))
71
        self.parser.add_argument('--decrypt', action='store_true',
72
                                 help='Decrypt secrets and display plain text.')
73
74
    def run_and_print(self, args, **kwargs):
75
        if args.prefix:
76
            kwargs['prefix'] = args.prefix
77
78
        decrypt = getattr(args, 'decrypt', False)
79
        kwargs['params'] = {'decrypt': str(decrypt).lower()}
80
81
        instances = self.run(args, **kwargs)
82
        self.print_output(reversed(instances), table.MultiColumnTable,
83
                          attributes=args.attr, widths=args.width,
84
                          json=args.json,
85
                          attribute_transform_functions=self.attribute_transform_functions)
86
87
88
class KeyValuePairGetCommand(resource.ResourceGetCommand):
89
    pk_argument_name = 'name'
90
    display_attributes = ['name', 'value', 'secret', 'encrypted', 'expire_timestamp']
91
92
    def __init__(self, kv_resource, *args, **kwargs):
93
        super(KeyValuePairGetCommand, self).__init__(kv_resource, *args, **kwargs)
94
        self.parser.add_argument('-d', '--decrypt', action='store_true',
95
                                 help='Decrypt secret if encrypted and show plain text.')
96
97
    @resource.add_auth_token_to_kwargs_from_cli
98
    def run(self, args, **kwargs):
99
        resource_name = getattr(args, self.pk_argument_name, None)
100
        decrypt = getattr(args, 'decrypt', False)
101
        kwargs['params'] = {'decrypt': str(decrypt).lower()}
102
        return self.get_resource_by_id(id=resource_name, **kwargs)
103
104
105
class KeyValuePairSetCommand(resource.ResourceCommand):
106
    display_attributes = ['name', 'value', 'expire_timestamp']
107
108
    def __init__(self, resource, *args, **kwargs):
0 ignored issues
show
Comprehensibility Bug introduced by
resource is re-defining a name which is already available in the outer-scope (previously defined on line 21).

It is generally a bad practice to shadow variables from the outer-scope. In most cases, this is done unintentionally and might lead to unexpected behavior:

param = 5

class Foo:
    def __init__(self, param):   # "param" would be flagged here
        self.param = param
Loading history...
109
        super(KeyValuePairSetCommand, self).__init__(
110
            resource, 'set',
111
            'Set an existing %s.' % resource.get_display_name().lower(),
112
            *args, **kwargs
113
        )
114
115
        self.parser.add_argument('name',
116
                                 metavar='name',
117
                                 help='Name of the key value pair.')
118
        self.parser.add_argument('value', help='Value paired with the key.')
119
        self.parser.add_argument('-l', '--ttl', dest='ttl', type=int, default=None,
120
                                 help='TTL (in seconds) for this value.')
121
        self.parser.add_argument('-e', '--encrypt', dest='secret',
122
                                 action='store_true',
123
                                 help='Encrypt value before saving the value.')
124
125
    @add_auth_token_to_kwargs_from_cli
126
    def run(self, args, **kwargs):
127
        instance = KeyValuePair()
128
        instance.id = args.name  # TODO: refactor and get rid of id
129
        instance.name = args.name
130
        instance.value = args.value
131
132
        if args.secret:
133
            instance.secret = args.secret
134
135
        if args.ttl:
136
            instance.ttl = args.ttl
137
138
        return self.manager.update(instance, **kwargs)
139
140
    def run_and_print(self, args, **kwargs):
141
        instance = self.run(args, **kwargs)
142
        self.print_output(instance, table.PropertyValueTable,
143
                          attributes=self.display_attributes, json=args.json)
144
145
146
class KeyValuePairDeleteCommand(resource.ResourceDeleteCommand):
147
    pk_argument_name = 'name'
148
149
    @add_auth_token_to_kwargs_from_cli
150
    def run(self, args, **kwargs):
151
        resource_id = getattr(args, self.pk_argument_name, None)
152
        instance = self.get_resource(resource_id, **kwargs)
153
154
        if not instance:
155
            raise resource.ResourceNotFoundError('KeyValuePair with id "%s" not found', resource_id)
156
157
        instance.id = resource_id  # TODO: refactor and get rid of id
158
        self.manager.delete(instance, **kwargs)
159
160
161
class KeyValuePairDeleteByPrefixCommand(resource.ResourceCommand):
162
    """
163
    Commands which delete all the key value pairs which match the provided
164
    prefix.
165
    """
166
    def __init__(self, resource, *args, **kwargs):
0 ignored issues
show
Comprehensibility Bug introduced by
resource is re-defining a name which is already available in the outer-scope (previously defined on line 21).

It is generally a bad practice to shadow variables from the outer-scope. In most cases, this is done unintentionally and might lead to unexpected behavior:

param = 5

class Foo:
    def __init__(self, param):   # "param" would be flagged here
        self.param = param
Loading history...
167
        super(KeyValuePairDeleteByPrefixCommand, self).__init__(resource, 'delete_by_prefix',
168
            'Delete KeyValue pairs which match the provided prefix', *args, **kwargs)
169
170
        self.parser.add_argument('-p', '--prefix', required=True,
171
                                 help='Name prefix (e.g. twitter.TwitterSensor:)')
172
173
    @add_auth_token_to_kwargs_from_cli
174
    def run(self, args, **kwargs):
175
        prefix = args.prefix
176
        key_pairs = self.manager.get_all(prefix=prefix)
177
178
        to_delete = []
179
        for key_pair in key_pairs:
180
            key_pair.id = key_pair.name
181
            to_delete.append(key_pair)
182
183
        deleted = []
184
        for key_pair in to_delete:
185
            self.manager.delete(instance=key_pair, **kwargs)
186
            deleted.append(key_pair)
187
188
        return deleted
189
190
    def run_and_print(self, args, **kwargs):
191
        # TODO: Need to use args, instead of kwargs (args=) because of bad API
192
        # FIX ME
193
        deleted = self.run(args, **kwargs)
194
        key_ids = [key_pair.id for key_pair in deleted]
195
196
        print('Deleted %s keys' % (len(deleted)))
197
        print('Deleted key ids: %s' % (', '.join(key_ids)))
198
199
200
class KeyValuePairLoadCommand(resource.ResourceCommand):
201
    pk_argument_name = 'name'
202
    display_attributes = ['name', 'value']
203
204
    def __init__(self, resource, *args, **kwargs):
0 ignored issues
show
Comprehensibility Bug introduced by
resource is re-defining a name which is already available in the outer-scope (previously defined on line 21).

It is generally a bad practice to shadow variables from the outer-scope. In most cases, this is done unintentionally and might lead to unexpected behavior:

param = 5

class Foo:
    def __init__(self, param):   # "param" would be flagged here
        self.param = param
Loading history...
205
        help_text = ('Load a list of %s from file.' %
206
                     resource.get_plural_display_name().lower())
207
        super(KeyValuePairLoadCommand, self).__init__(resource, 'load',
208
            help_text, *args, **kwargs)
209
210
        self.parser.add_argument(
211
            'file', help=('JSON file containing the %s to create.'
212
                          % resource.get_plural_display_name().lower()))
213
214
    @add_auth_token_to_kwargs_from_cli
215
    def run(self, args, **kwargs):
216
        file_path = os.path.normpath(pjoin(os.getcwd(), args.file))
217
218
        if not os.path.exists(args.file):
219
            raise ValueError('File "%s" doesn\'t exist' % (file_path))
220
221
        if not os.path.isfile(args.file):
222
            raise ValueError('"%s" is not a file' % (file_path))
223
224
        with open(file_path, 'r') as f:
225
            kvps = json.loads(f.read())
226
227
        instances = []
228
        for item in kvps:
229
            name = item['name']
230
            value = item['value']
231
232
            instance = KeyValuePair()
233
            instance.id = name  # TODO: refactor and get rid of id
234
            instance.name = name
235
            instance.value = value
236
237
            self.manager.update(instance, **kwargs)
238
            instances.append(instance)
239
        return instances
240
241
    def run_and_print(self, args, **kwargs):
242
        instances = self.run(args, **kwargs)
243
        self.print_output(instances, table.MultiColumnTable,
244
                          attributes=['id', 'name', 'value'], json=args.json)
245