Skip to content

Commit bcb426a

Browse files
committed
Merge pull request #17 from spry-group/master
Release Candidate, 0.1.2
2 parents b4b942f + 40cf01f commit bcb426a

File tree

7 files changed

+124
-40
lines changed

7 files changed

+124
-40
lines changed

.travis.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
language: python
22
python:
3-
- "2.6"
43
- "2.7"
54
- "3.2"
65
- "3.3"

CONTRIBUTING.md

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,17 @@
22

33
Vultr is a client library for the Vultr API.
44

5-
## Bug Reports
5+
## Bug Reports
66

77
Please report bugs through the github issue queue. When reporting a bug please include a code sample, describe the behavior you expect, and the behavior you're observing.
88

99
## Contributing Code
1010

11-
Vultr is maintained on Github. Changes should be submitted as pull requests rebased on the latest master.
11+
Vultr is maintained on Github. Changes should be submitted as pull requests rebased on the latest master.
1212

1313
## Becoming a Maintainer
1414

15-
Please send an email to darrel.opry@spry-group.com if you are interested in becoming a maintainer. Like all open source projects, the more hands the merrier.
15+
Please send an email to darrel.opry@spry-group.com if you are interested in becoming a maintainer. Like all open source projects, the more hands the merrier.
1616

1717
## Development
1818

@@ -21,4 +21,28 @@ Please send an email to darrel.opry@spry-group.com if you are interested in beco
2121
2222
```
2323

24-
## Testing
24+
## Testing
25+
26+
Tests spawn and destroy instances labelled 'python-vultr: test'
27+
28+
I highly recommend you setup a Vultr account specifically for integration testing with
29+
this library to avoid unintentionally destroying servers you need.
30+
31+
Be sure to clean up your Vultr account when done.
32+
33+
```
34+
python setup.py test
35+
```
36+
37+
## Release Process
38+
39+
Releases are tracked by creating a pull request from master to release. Ensure the version has been properly upticked before creating the release candidate pull request. The merged commit should be tagged with the proper version and built and uploaded to pypi. Currently the release process is manual. Once a more mature testing suite in place, it should be automated with TravisCI.
40+
41+
```
42+
python setup.py sdist
43+
python setup.py bdist_wheel
44+
python setup.py sdist upload -r pypi
45+
python setup.py bdist_wheel upload -r pypi
46+
```
47+
48+
based on: [Sharing Your Labor of Love: PyPI Quick and Dirty](https://hynek.me/articles/sharing-your-labor-of-love-pypi-quick-and-dirty/)

README.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,17 @@ Vultr provides a client library to the Vultr.com API.
1515
plans_json = vultr.plans_list()
1616

1717

18+
**Support**
19+
20+
21+
Python Vultr is supported on a volunteer basis.
22+
23+
* `Open an Issue <https://github.com/spry-group/python-vultr/issues/new>`_
24+
25+
* .. image:: https://badges.gitter.im/Join%20Chat.svg
26+
:target: https://gitter.im/spry-group/python-vultr
27+
28+
1829
**API**
1930

2031

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ def read(filename):
1212

1313
setup(
1414
name='vultr',
15-
version='0.1.1',
15+
version='0.1.2',
1616
install_requires=[
1717
"requests"
1818
],

tests/test_vultr.py

Lines changed: 48 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,26 +22,18 @@ def test_app_list(self):
2222
response = self.vultr.app_list()
2323

2424

25+
@unittest.skipIf(not os.environ.get('VULTR_KEY'), 'Skipping AuthenticatedTests')
2526
class AuthenticatedTests(unittest.TestCase):
26-
27-
def setUp(self):
28-
self.VULTR_KEY = os.environ.get('VULTR_KEY')
29-
30-
if self.VULTR_KEY is None:
31-
warnings.warn('The VULTR_KEY environment variable is not ' +
32-
'set. AuthenticatedTests will be bypassed.',
33-
UserWarning)
34-
else:
35-
self.vultr = Vultr(self.VULTR_KEY)
27+
@classmethod
28+
def setUpClass(cls):
29+
cls.VULTR_KEY = os.environ.get('VULTR_KEY')
30+
cls.vultr = Vultr(cls.VULTR_KEY)
31+
cls.server_list = {}
3632

3733
def test_get_api_key(self):
38-
if self.VULTR_KEY is None:
39-
return
4034
response = self.vultr.iso_list()
4135

4236
def test_post_api_key(self):
43-
if self.VULTR_KEY is None:
44-
return
4537
try:
4638
response = self.vultr.server_label_set('', '')
4739
except VultrError as e:
@@ -52,5 +44,47 @@ def test_post_api_key(self):
5244
" ensure your API key matches the server's" +
5345
" account")
5446

47+
def test_account_info(self):
48+
response = self.vultr.account_info()
49+
50+
def test_server_create(self):
51+
response = self.vultr.server_create(vpsplanid=29, dcid=1, osid=191,
52+
label="python-vultr: test")
53+
warnings.warn("Creating VM: " + str(response) +
54+
"\n This will cost money.")
55+
56+
def test_server_list(self):
57+
AuthenticatedTests.server_list = self.vultr.server_list()
58+
warnings.warn(str(AuthenticatedTests.server_list))
59+
60+
def test_server_list_by_subid(self):
61+
for subid in AuthenticatedTests.server_list:
62+
response = self.vultr.server_list(subid=subid)
63+
64+
def test_server_destroy(self):
65+
servers = self.vultr.server_list()
66+
for subid in servers:
67+
# skip machines not made by tests.
68+
69+
if servers[subid]['label'] != 'python-vultr: test':
70+
warnings.warn("skipping [" + subid + "]:\n" +
71+
str(servers[subid]))
72+
continue
73+
74+
try:
75+
response = self.vultr.server_destroy(subid=subid)
76+
except VultrError as e:
77+
# This should be it's own
78+
# except VultrServerDestroyWithinFiveMinutesError as e:
79+
msg = str(e)
80+
self.assertEqual(msg, "Request failed. Check the response" +
81+
" body for a more detailed" +
82+
" description. Body: \nUnable to" +
83+
" destroy server: Servers cannot be" +
84+
" destroyed within 5 minutes of being" +
85+
" created")
86+
87+
warnings.warn(msg)
88+
5589
if __name__ == '__main__':
5690
unittest.main()

vultr/__init__.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
__version__ = '0.1.1'
2-
__license__ = 'MIT'
3-
41
from .vultr import Vultr, VultrError
2+
__version__ = '0.1.2'
3+
__license__ = 'MIT'

vultr/vultr.py

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import sys
22
import requests
3+
import time
34
import json as json_module
4-
5+
from os import environ
56
API_ENDPOINT = 'https://api.vultr.com'
67

78

@@ -14,6 +15,8 @@ class Vultr(object):
1415
def __init__(self, api_key):
1516
self.api_endpoint = API_ENDPOINT
1617
self.api_key = api_key
18+
self.requestsPerSecond = 1
19+
self.requestDuration = 1 / self.requestsPerSecond
1720

1821
def snapshot_list(self):
1922
"""
@@ -563,7 +566,7 @@ def backup_list(self):
563566
"""
564567
return self.request('/v1/backup/list')
565568

566-
def server_list(self, subid):
569+
def server_list(self, subid=None):
567570
"""
568571
/v1/server/list
569572
GET - account
@@ -615,7 +618,7 @@ def server_list(self, subid):
615618
params = {'SUBID': subid}
616619
return self.request('/v1/server/list', params)
617620

618-
def server_bandwidth(self):
621+
def server_bandwidth(self, subid):
619622
"""
620623
/v1/server/bandwidth
621624
GET - account
@@ -670,7 +673,7 @@ def server_bandwidth(self):
670673
params = {'SUBID': subid}
671674
return self.request('/v1/server/bandwidth', params)
672675

673-
def server_reboot(self):
676+
def server_reboot(self, subid):
674677
"""
675678
/v1/server/reboot
676679
POST - account
@@ -688,7 +691,7 @@ def server_reboot(self):
688691
params = {'SUBID': subid}
689692
return self.request('/v1/server/reboot', params, 'POST')
690693

691-
def server_halt(self):
694+
def server_halt(self, subid):
692695
"""
693696
/v1/server/halt
694697
POST - account
@@ -708,7 +711,7 @@ def server_halt(self):
708711
params = {'SUBID': subid}
709712
return self.request('/v1/server/halt', params, 'POST')
710713

711-
def server_start(self):
714+
def server_start(self, subid):
712715
"""
713716
/v1/server/start
714717
POST - account
@@ -726,7 +729,7 @@ def server_start(self):
726729
params = {'SUBID': subid}
727730
return self.request('/v1/server/start', params, 'POST')
728731

729-
def server_destroy(self):
732+
def server_destroy(self, subid):
730733
"""
731734
/v1/server/destroy
732735
POST - account
@@ -745,7 +748,7 @@ def server_destroy(self):
745748
params = {'SUBID': subid}
746749
return self.request('/v1/server/destroy', params, 'POST')
747750

748-
def server_reinstall(self):
751+
def server_reinstall(self, subid):
749752
"""
750753
/v1/server/reinstall
751754
POST - account
@@ -924,7 +927,7 @@ def server_list_ipv4(self, subid):
924927
params = {'SUBID': subid}
925928
return self.request('/v1/server/list_ipv4', params)
926929

927-
def server_reverse_set_ipv4(self):
930+
def server_reverse_set_ipv4(self, subid, ip, entry):
928931
"""
929932
/v1/server/reverse_set_ipv4
930933
POST - account
@@ -967,7 +970,7 @@ def server_reverse_default_ipv4(self, subid, ip):
967970
params = {'SUBID': subid, 'ip': ip}
968971
return self.request('/v1/server/reverse_default_ipv4', params, 'POST')
969972

970-
def server_list_ipv6(self):
973+
def server_list_ipv6(self, subid):
971974
"""
972975
/v1/server/list_ipv6
973976
GET - account
@@ -995,7 +998,7 @@ def server_list_ipv6(self):
995998
params = {'SUBID': subid}
996999
return self.request('/v1/server/list_ipv6', params)
9971000

998-
def server_reverse_list_ipv6(self):
1001+
def server_reverse_list_ipv6(self, subid):
9991002
"""
10001003
/v1/server/reverse_list_ipv6
10011004
GET - account
@@ -1130,7 +1133,7 @@ def server_destroy_ipv4(self, subid, ip):
11301133
params = {'SUBID': subid, 'ip': ip}
11311134
return self.request('/v1/server/destroy_ipv4', params, 'POST')
11321135

1133-
def server_os_change_list(self):
1136+
def server_os_change_list(self, subid):
11341137
"""
11351138
/v1/server/os_change_list
11361139
GET - account
@@ -1185,7 +1188,7 @@ def server_os_change(self, subid, osid):
11851188
params = {'SUBID': subid, 'OSID': osid}
11861189
return self.request('/v1/server/os_change', params)
11871190

1188-
def server_upgrade_plan_list(self):
1191+
def server_upgrade_plan_list(self, subid):
11891192
"""
11901193
/v1/server/upgrade_plan_list
11911194
GET - account
@@ -1309,17 +1312,21 @@ def os_list(self):
13091312
return self.request('/v1/os/list')
13101313

13111314
def request(self, path, params={}, method='GET'):
1315+
_start = time.time()
1316+
13121317
if not path.startswith('/'):
13131318
path = '/' + path
13141319
url = self.api_endpoint + path
13151320

13161321
try:
13171322
if method == 'POST':
1318-
query = {'api_key': self.api_key}
1323+
if (self.api_key):
1324+
query = {'api_key': self.api_key}
13191325
resp = requests.post(url, params=query, data=params,
13201326
timeout=60)
13211327
elif method == 'GET':
1322-
params['api_key'] = self.api_key
1328+
if (self.api_key):
1329+
params['api_key'] = self.api_key
13231330
resp = requests.get(url, params=params, timeout=60)
13241331
else:
13251332
raise VultrError('Unsupported method %s' % method)
@@ -1351,14 +1358,24 @@ def request(self, path, params={}, method='GET'):
13511358
' to an average of 1/s. Try your request' +
13521359
' again later.')
13531360

1354-
return resp.json()
1361+
# very simplistic synchronous rate limiting;
1362+
_elapsed = time.time() - _start
1363+
if (_elapsed < self.requestDuration):
1364+
time.sleep(self.requestDuration - _elapsed)
1365+
1366+
# return an empty json object if the API
1367+
# doesn't respond with a value.
1368+
if not resp.text:
1369+
return json_module.loads('{}')
1370+
else:
1371+
return resp.json()
13551372

13561373

13571374
if __name__ == '__main__':
13581375
print("Vultr API Python Libary")
13591376
print("http://vultr.com")
13601377

1361-
api_key = ''
1378+
api_key = environ.get('VULTR_KEY')
13621379
if len(sys.argv) > 1:
13631380
api_key = sys.argv[1]
13641381

0 commit comments

Comments
 (0)