Passed
Push — master ( cf341e...dcdf4c )
by
unknown
03:07
created

get_pack_common_libs_path()   A

Complexity

Conditions 2

Size

Total Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
c 0
b 0
f 0
dl 0
loc 23
rs 9.0856
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 re
18
19
import jsonschema
20
21
from st2common.util import schema as util_schema
22
from st2common.constants.pack import MANIFEST_FILE_NAME
23
from st2common.constants.pack import PACK_REF_WHITELIST_REGEX
24
from st2common.content.loader import MetaLoader
25
26
__all__ = [
27
    'get_pack_ref_from_metadata',
28
    'get_pack_metadata',
29
30
    'validate_config_against_schema',
31
32
    'normalize_pack_version'
33
]
34
35
36
def get_pack_ref_from_metadata(metadata, pack_directory_name=None):
37
    """
38
    Utility function which retrieves pack "ref" attribute from the pack metadata file.
39
40
    If this attribute is not provided, an attempt is made to infer "ref" from the "name" attribute.
41
42
    :rtype: ``str``
43
    """
44
    pack_ref = None
45
46
    # The rules for the pack ref are as follows:
47
    # 1. If ref attribute is available, we used that
48
    # 2. If pack_directory_name is available we use that (this only applies to packs
49
    # which are in sub-directories)
50
    # 2. If attribute is not available, but pack name is and pack name meets the valid name
51
    # criteria, we use that
52
    if metadata.get('ref', None):
53
        pack_ref = metadata['ref']
54
    elif pack_directory_name and re.match(PACK_REF_WHITELIST_REGEX, pack_directory_name):
55
        pack_ref = pack_directory_name
56
    else:
57
        if re.match(PACK_REF_WHITELIST_REGEX, metadata['name']):
58
            pack_ref = metadata['name']
59
        else:
60
            msg = ('Pack name "%s" contains invalid characters and "ref" attribute is not '
61
                   'available. You either need to add "ref" attribute which contains only word '
62
                   'characters to the pack metadata file or update name attribute to contain only'
63
                   'word characters.')
64
            raise ValueError(msg % (metadata['name']))
65
66
    return pack_ref
67
68
69
def get_pack_metadata(pack_dir):
70
    """
71
    Return parsed metadata for a particular pack directory.
72
73
    :rtype: ``dict``
74
    """
75
    manifest_path = os.path.join(pack_dir, MANIFEST_FILE_NAME)
76
77
    if not os.path.isfile(manifest_path):
78
        raise ValueError('Pack "%s" is missing %s file' % (pack_dir, MANIFEST_FILE_NAME))
79
80
    meta_loader = MetaLoader()
81
    content = meta_loader.load(manifest_path)
82
    if not content:
83
        raise ValueError('Pack "%s" metadata file is empty' % (pack_dir))
84
85
    return content
86
87
88
def validate_config_against_schema(config_schema, config_object, config_path,
89
                                  pack_name=None):
90
    """
91
    Validate provided config dictionary against the provided config schema
92
    dictionary.
93
    """
94
    pack_name = pack_name or 'unknown'
95
96
    schema = util_schema.get_schema_for_resource_parameters(parameters_schema=config_schema,
97
                                                            allow_additional_properties=True)
98
    instance = config_object
99
100
    try:
101
        cleaned = util_schema.validate(instance=instance, schema=schema,
102
                                       cls=util_schema.CustomValidator, use_default=True,
103
                                       allow_default_none=True)
104
    except jsonschema.ValidationError as e:
105
        attribute = getattr(e, 'path', [])
106
        attribute = '.'.join(attribute)
107
108
        msg = ('Failed validating attribute "%s" in config for pack "%s" (%s): %s' %
109
               (attribute, pack_name, config_path, str(e)))
110
        raise jsonschema.ValidationError(msg)
111
112
    return cleaned
113
114
115
def get_pack_common_libs_path(pack_db):
116
    """
117
    Return the pack's common lib path. This is the path where common code for sensors
118
    and actions are placed.
119
120
    For example, if the pack is at /opt/stackstorm/packs/my_pack, you can place
121
    common library code for actions and sensors in /opt/stackstorm/packs/my_pack/lib/.
122
    This common library code is only available for python sensors and actions. The lib
123
    structure also needs to follow a python convention with a __init__.py file.
124
125
    :param pack_db: Pack DB model
126
    :type pack_db: :class:`PackDB`
127
128
    :rtype: ``str``
129
    """
130
    pack_dir = getattr(pack_db, 'path', None)
131
132
    if not pack_dir:
133
        return None
134
135
    libs_path = os.path.join(pack_dir, 'lib')
136
137
    return libs_path
138
139
140
def normalize_pack_version(version):
141
    """
142
    Normalize old, pre StackStorm v2.1 non valid semver version string (e.g. 0.2) to a valid
143
    semver version string (0.2.0).
144
145
    :rtype: ``str``
146
    """
147
    version = str(version)
148
149
    version_seperator_count = version.count('.')
150
    if version_seperator_count == 1:
151
        version = version + '.0'
152
153
    return version
154