1# Licensed to the Apache Software Foundation (ASF) 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"""
17Common methods for obtaining a reference to the provider driver class.
18"""
19
20__all__ = [
21    'get_driver',
22    'set_driver'
23]
24
25
26def get_driver(drivers, provider, deprecated_providers=None,
27               deprecated_constants=None):
28    """
29    Get a driver.
30
31    :param drivers: Dictionary containing valid providers.
32    :type drivers: ``dict``
33
34    :param provider: Id (constant) of provider to get the driver for.
35    :type provider: :class:`libcloud.types.Provider`
36
37    :param: deprecated_providers: Dictionary with information about the
38            deprecated drivers.
39    :type deprecated_providers: ``dict``
40
41    :param: deprecated_constants: Dictionary with information about the
42            deprecated provider constants.
43    :type deprecated_constants: ``dict``
44    """
45    # Those providers have been shut down or similar.
46    deprecated_providers = deprecated_providers or {}
47    if provider in deprecated_providers:
48        url = deprecated_providers[provider]['url']
49        reason = deprecated_providers[provider]['reason']
50        msg = ('Provider no longer supported: %s, please visit: %s' %
51               (url, reason))
52        raise Exception(msg)
53
54    # Those drivers have moved to "region" constructor argument model
55    deprecated_constants = deprecated_constants or {}
56    if provider in deprecated_constants:
57        old_name = provider.upper()
58        new_name = deprecated_constants[provider].upper()
59
60        url = 'https://s.apache.org/lc0140un'
61        msg = ('Provider constant "%s" has been removed. New constant '
62               'is now called "%s".\n'
63               'For more information on this change and how to modify your '
64               'code to work with it, please visit: %s' %
65               (old_name, new_name, url))
66        raise Exception(msg)
67
68    if provider in drivers:
69        mod_name, driver_name = drivers[provider]
70        _mod = __import__(mod_name, globals(), locals(), [driver_name])
71        return getattr(_mod, driver_name)
72
73    # NOTE: This is for backward compatibility reasons where user could use
74    # a string value instead of a Provider.FOO enum constant and this function
75    # would still work
76    for provider_name, (mod_name, driver_name) in drivers.items():
77        # NOTE: This works because Provider enum class overloads __eq__
78        if provider.lower() == provider_name.lower():
79            _mod = __import__(mod_name, globals(), locals(), [driver_name])
80            return getattr(_mod, driver_name)
81
82    raise AttributeError('Provider %s does not exist' % (provider))
83
84
85def set_driver(drivers, provider, module, klass):
86    """
87    Sets a driver.
88
89    :param drivers: Dictionary to store providers.
90    :param provider: Id of provider to set driver for
91
92    :type provider: :class:`libcloud.types.Provider`
93    :param module: The module which contains the driver
94
95    :type module: L
96    :param klass: The driver class name
97
98    :type klass:
99    """
100
101    if provider in drivers:
102        raise AttributeError('Provider %s already registered' % (provider))
103
104    drivers[provider] = (module, klass)
105
106    # Check if this driver is valid
107    try:
108        driver = get_driver(drivers, provider)
109    except (ImportError, AttributeError) as exp:
110        drivers.pop(provider)
111        raise exp
112
113    return driver
114