Skip to content

Commit d3ffa85

Browse files
committed
Added support for profiles - see README
1 parent 12836e3 commit d3ffa85

File tree

5 files changed

+128
-16
lines changed

5 files changed

+128
-16
lines changed

CloudFlare/cloudflare.py

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class CloudFlare(object):
1919
class _v4base(object):
2020
""" Cloudflare v4 API"""
2121

22-
def __init__(self, email, token, certtoken, base_url, debug, raw, use_sessions):
22+
def __init__(self, email, token, certtoken, base_url, debug, raw, use_sessions, profile):
2323
""" Cloudflare v4 API"""
2424

2525
self.email = email
@@ -28,6 +28,7 @@ def __init__(self, email, token, certtoken, base_url, debug, raw, use_sessions):
2828
self.base_url = base_url
2929
self.raw = raw
3030
self.use_sessions = use_sessions
31+
self.profile = profile
3132
self.session = None
3233
self.user_agent = user_agent()
3334

@@ -821,13 +822,16 @@ def api_list(self, m=None, s=''):
821822
w = w + self.api_list(a, s + '/' + n)
822823
return w
823824

824-
def __init__(self, email=None, token=None, certtoken=None, debug=False, raw=False, use_sessions=True):
825+
def __init__(self, email=None, token=None, certtoken=None, debug=False, raw=False, use_sessions=True, profile=None):
825826
""" Cloudflare v4 API"""
826827

827828
base_url = BASE_URL
828829

829830
# class creation values override configuration values
830-
[conf_email, conf_token, conf_certtoken, extras] = read_configs()
831+
try:
832+
[conf_email, conf_token, conf_certtoken, extras] = read_configs(profile)
833+
except:
834+
raise CloudFlareAPIError(0, 'profile/configuration read error')
831835

832836
if email is None:
833837
email = conf_email
@@ -842,7 +846,7 @@ def __init__(self, email=None, token=None, certtoken=None, debug=False, raw=Fals
842846
token = None
843847
if certtoken == '':
844848
certtoken = None
845-
self._base = self._v4base(email, token, certtoken, base_url, debug, raw, use_sessions)
849+
self._base = self._v4base(email, token, certtoken, base_url, debug, raw, use_sessions, profile)
846850

847851
# add the API calls
848852
api_v4(self)
@@ -871,21 +875,21 @@ def __str__(self):
871875
if self._base.email is None:
872876
return '["%s"]' % ('REDACTED')
873877
else:
874-
return '["%s","%s"]' % (self._base.email, 'REDACTED')
878+
return '["%s","%s","%s"]' % (self._base.profile, self._base.email, 'REDACTED')
875879

876880
def __repr__(self):
877881
""" Cloudflare v4 API"""
878882

879883
if self._base.email is None:
880-
return '%s,%s(%s,"%s","%s",%s,"%s")' % (
884+
return '%s,%s(%s,"%s","%s","%s",%s,"%s")' % (
881885
self.__module__, type(self).__name__,
882-
'REDACTED', 'REDACTED',
886+
self._base.profile, 'REDACTED', 'REDACTED',
883887
self._base.base_url, self._base.raw, self._base.user_agent
884888
)
885889
else:
886-
return '%s,%s(%s,"%s","%s","%s",%s,"%s")' % (
890+
return '%s,%s(%s,"%s","%s","%s","%s",%s,"%s")' % (
887891
self.__module__, type(self).__name__,
888-
self._base.email, 'REDACTED', 'REDACTED',
892+
self._base.profile, self._base.email, 'REDACTED', 'REDACTED',
889893
self._base.base_url, self._base.raw, self._base.user_agent
890894
)
891895

CloudFlare/read_configs.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
except ImportError:
88
import configparser as ConfigParser # py3
99

10-
def read_configs():
10+
def read_configs(profile=None):
1111
""" reading the config file for Cloudflare API"""
1212

1313
# envioronment variables override config files
@@ -24,27 +24,39 @@ def read_configs():
2424
os.path.expanduser('~/.cloudflare/cloudflare.cfg')
2525
])
2626

27+
if profile is None:
28+
profile = 'CloudFlare'
29+
30+
if len(config.sections()) == 0:
31+
## no config file found - so env values (even if empty) should be returned
32+
## this isn't an error
33+
return [email, token, certtoken, extras]
34+
35+
if profile not in config.sections():
36+
## section is missing - this is an error
37+
raise
38+
2739
if email is None:
2840
try:
29-
email = re.sub(r"\s+", '', config.get('CloudFlare', 'email'))
41+
email = re.sub(r"\s+", '', config.get(profile, 'email'))
3042
except (ConfigParser.NoOptionError, ConfigParser.NoSectionError):
3143
email = None
3244

3345
if token is None:
3446
try:
35-
token = re.sub(r"\s+", '', config.get('CloudFlare', 'token'))
47+
token = re.sub(r"\s+", '', config.get(profile, 'token'))
3648
except (ConfigParser.NoOptionError, ConfigParser.NoSectionError):
3749
token = None
3850

3951
if certtoken is None:
4052
try:
41-
certtoken = re.sub(r"\s+", '', config.get('CloudFlare', 'certtoken'))
53+
certtoken = re.sub(r"\s+", '', config.get(profile, 'certtoken'))
4254
except (ConfigParser.NoOptionError, ConfigParser.NoSectionError):
4355
certtoken = None
4456

4557
if extras is None:
4658
try:
47-
extras = re.sub(r"\s+", ' ', config.get('CloudFlare', 'extras'))
59+
extras = re.sub(r"\s+", ' ', config.get(profile, 'extras'))
4860
except (ConfigParser.NoOptionError, ConfigParser.NoSectionError):
4961
extras = None
5062

README.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,9 @@ import CloudFlare
194194

195195
# An authenticated call using an API Key and CA-Origin info
196196
cf = CloudFlare.CloudFlare(email='user@example.com', token='00000000000000000000000000000000', certtoken='v1.0-...')
197+
198+
# An authenticated call using using a stored profile (see below)
199+
cf = CloudFlare.CloudFlare(profile="CompanyX"))
197200
```
198201

199202
If the account email and API key are not passed when you create the class, then they are retrieved from either the users exported shell environment variables or the .cloudflare.cfg or ~/.cloudflare.cfg or ~/.cloudflare/cloudflare.cfg files, in that order.
@@ -203,6 +206,7 @@ If you're using an API Token, any `cloudflare.cfg` file must either not contain
203206
There is one call that presently doesn't need any email or token certification (the */ips* call); hence you can test without any values saved away.
204207

205208
### Using shell environment variables
209+
206210
```bash
207211
$ export CF_API_EMAIL='user@example.com' # Do not set if using an API Token
208212
$ export CF_API_KEY='00000000000000000000000000000000'
@@ -224,6 +228,45 @@ extras =
224228
$
225229
```
226230

231+
More than one profile can be stored within that file.
232+
Here's an example for a work and home setup (in this example work has an API Token and home uses email/token).
233+
234+
```bash
235+
$ cat ~/.cloudflare/cloudflare.cfg
236+
[Work]
237+
token = 00000000000000000000000000000000
238+
[Home]
239+
email = home@example.com
240+
token = 00000000000000000000000000000000
241+
$
242+
```
243+
244+
To select a profile, use the `--profile profile-name` option for `cli4` command or use `profile="profile-name"` in the library call.
245+
246+
```bash
247+
$ cli4 --profile Work /zones | jq '.[]|.name' | wc -l
248+
13
249+
$
250+
251+
$ cli4 --profile Home /zones | jq '.[]|.name' | wc -l
252+
1
253+
$
254+
```
255+
256+
Here is the same in code.
257+
258+
```python
259+
#!/usr/bin/env python
260+
261+
import CloudFlare
262+
263+
def main():
264+
cf = CloudFlare.CloudFlare(profile="Work")
265+
...
266+
```
267+
268+
### About /certificates and certtoken
269+
227270
The *CF_API_CERTKEY* or *certtoken* values are used for the Origin-CA */certificates* API calls.
228271
You can leave *certtoken* in the configuration with a blank value (or omit the option variable fully).
229272

README.rst

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,9 @@ parameters.
220220
# An authenticated call using an API Key and CA-Origin info
221221
cf = CloudFlare.CloudFlare(email='user@example.com', token='00000000000000000000000000000000', certtoken='v1.0-...')
222222
223+
# An authenticated call using using a stored profile (see below)
224+
cf = CloudFlare.CloudFlare(profile="CompanyX"))
225+
223226
If the account email and API key are not passed when you create the
224227
class, then they are retrieved from either the users exported shell
225228
environment variables or the .cloudflare.cfg or ~/.cloudflare.cfg or
@@ -261,6 +264,48 @@ Using configuration file to store email and keys
261264
extras =
262265
$
263266
267+
More than one profile can be stored within that file. Here's an example
268+
for a work and home setup (in this example work has an API Token and
269+
home uses email/token).
270+
271+
.. code:: bash
272+
273+
$ cat ~/.cloudflare/cloudflare.cfg
274+
[Work]
275+
token = 00000000000000000000000000000000
276+
[Home]
277+
email = home@example.com
278+
token = 00000000000000000000000000000000
279+
$
280+
281+
To select a profile, use the ``--profile profile-name`` option for
282+
``cli4`` command or use ``profile="profile-name"`` in the library call.
283+
284+
.. code:: bash
285+
286+
$ cli4 --profile Work /zones | jq '.[]|.name' | wc -l
287+
13
288+
$
289+
290+
$ cli4 --profile Home /zones | jq '.[]|.name' | wc -l
291+
1
292+
$
293+
294+
Here is the same in code.
295+
296+
.. code:: python
297+
298+
#!/usr/bin/env python
299+
300+
import CloudFlare
301+
302+
def main():
303+
cf = CloudFlare.CloudFlare(profile="Work")
304+
...
305+
306+
About /certificates and certtoken
307+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
308+
264309
The *CF\_API\_CERTKEY* or *certtoken* values are used for the Origin-CA
265310
*/certificates* API calls. You can leave *certtoken* in the
266311
configuration with a blank value (or omit the option variable fully).

cli4/cli4.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -213,25 +213,28 @@ def do_it(args):
213213
output = 'json'
214214
raw = False
215215
dump = False
216+
profile = None
216217
method = 'GET'
217218

218219
usage = ('usage: cli4 '
219220
+ '[-V|--version] [-h|--help] [-v|--verbose] [-q|--quiet] '
220221
+ '[-j|--json] [-y|--yaml] [-n|ndjson]'
221222
+ '[-r|--raw] '
222223
+ '[-d|--dump] '
224+
+ '[-p|--profile profile-name] '
223225
+ '[--get|--patch|--post|--put|--delete] '
224226
+ '[item=value|item=@filename|@filename ...] '
225227
+ '/command...')
226228

227229
try:
228230
opts, args = getopt.getopt(args,
229-
'VhvqjyrdGPOUD',
231+
'Vhvqjyrdp:GPOUD',
230232
[
231233
'version',
232234
'help', 'verbose', 'quiet', 'json', 'yaml', 'ndjson',
233235
'raw',
234236
'dump',
237+
'profile=',
235238
'get', 'patch', 'post', 'put', 'delete'
236239
])
237240
except getopt.GetoptError:
@@ -257,6 +260,8 @@ def do_it(args):
257260
output = 'ndjson'
258261
elif opt in ('-r', '--raw'):
259262
raw = True
263+
elif opt in ('-p', '--profile'):
264+
profile = arg;
260265
elif opt in ('-d', '--dump'):
261266
dump = True
262267
elif opt in ('-G', '--get'):
@@ -363,7 +368,10 @@ def do_it(args):
363368
exit(usage)
364369
command = args[0]
365370

366-
cf = CloudFlare.CloudFlare(debug=verbose, raw=raw)
371+
try:
372+
cf = CloudFlare.CloudFlare(debug=verbose, raw=raw, profile=profile)
373+
except Exception as e:
374+
exit(e)
367375
results = run_command(cf, method, command, params, content, files)
368376
write_results(results, output)
369377

0 commit comments

Comments
 (0)