File: transport.py

package info (click to toggle)
python-softlayer 6.2.5-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 7,508 kB
  • sloc: python: 57,195; makefile: 133; xml: 97; sh: 59
file content (161 lines) | stat: -rw-r--r-- 4,644 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
"""
    SoftLayer.transports.transport
    ~~~~~~~~~~~~~~~~~~~~
    Common functions for transporting API requests

    :license: MIT, see LICENSE for more details.
"""
import base64
import json
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry


from SoftLayer import utils


def get_session(user_agent):
    """Sets up urllib sessions"""

    client = requests.Session()
    client.headers.update({
        'Content-Type': 'application/json',
        'User-Agent': user_agent,
    })
    retry = Retry(total=3, connect=1, backoff_factor=1)
    adapter = HTTPAdapter(max_retries=retry)
    client.mount('https://', adapter)
    return client


# transports.Request does have a lot of instance attributes. :(
# pylint: disable=too-many-instance-attributes
class Request(object):
    """Transport request object."""

    def __init__(self):
        #: API service name. E.G. SoftLayer_Account
        self.service = None

        #: API method name. E.G. getObject
        self.method = None

        #: API Parameters.
        self.args = tuple()

        #: API headers, used for authentication, masks, limits, offsets, etc.
        self.headers = {}

        #: Transport user.
        self.transport_user = None

        #: Transport password.
        self.transport_password = None

        #: Transport headers.
        self.transport_headers = {}

        #: False -> Don't verify the SSL certificate
        #: True -> Verify the SSL certificate
        #: Path String -> Verify the SSL certificate with the .pem file at path
        self.verify = None

        #: Client certificate file path. (Used by X509Authentication)
        self.cert = None

        #: InitParameter/identifier of an object.
        self.identifier = None

        #: SoftLayer mask (dict or string).
        self.mask = None

        #: SoftLayer Filter (dict).
        self.filter = None

        #: Integer result limit.
        self.limit = None

        #: Integer result offset.
        self.offset = None

        #: Integer call start time
        self.start_time = None

        #: Integer call end time
        self.end_time = None

        #: String full url
        self.url = None

        #: String result of api call
        self.result = None

        #: String payload to send in
        self.payload = None

        #: Exception any exceptions that got caught
        self.exception = None

    def __repr__(self):
        """Prints out what this call is all about"""
        pretty_mask = utils.clean_string(self.mask)
        pretty_filter = self.filter
        clean_args = self.args
        # Passwords can show up here, so censor them before logging.
        if self.method in ["performExternalAuthentication", "refreshEncryptedToken", "getPortalLoginToken"]:
            clean_args = "*************"
        param_string = (f"id={self.identifier}, mask='{pretty_mask}', filter='{pretty_filter}', args={clean_args}, "
                        f"limit={self.limit}, offset={self.offset}")
        return "{service}::{method}({params})".format(
            service=self.service, method=self.method, params=param_string)


class SoftLayerListResult(list):
    """A SoftLayer API list result."""

    def __init__(self, items=None, total_count=0):

        #: total count of items that exist on the server. This is useful when
        #: paginating through a large list of objects.
        self.total_count = total_count
        super().__init__(items)


def _proxies_dict(proxy):
    """Makes a proxy dict appropriate to pass to requests."""
    if not proxy:
        return None
    return {'http': proxy, 'https': proxy}


def _format_object_mask(objectmask):
    """Format the new style object mask.

    This wraps the user mask with mask[USER_MASK] if it does not already
    have one. This makes it slightly easier for users.

    :param objectmask: a string-based object mask

    """
    objectmask = objectmask.strip()

    if (not objectmask.startswith('mask') and
            not objectmask.startswith('[') and
            not objectmask.startswith('filteredMask')):
        objectmask = "mask[%s]" % objectmask
    return objectmask


class ComplexEncoder(json.JSONEncoder):
    """ComplexEncoder helps jsonencoder deal with byte strings"""

    def default(self, o):
        """Encodes o as JSON"""

        # Base64 encode bytes type objects.
        if isinstance(o, bytes):
            base64_bytes = base64.b64encode(o)
            return base64_bytes.decode("utf-8")
        # Let the base class default method raise the TypeError
        return json.JSONEncoder.default(self, o)