merge master

This commit is contained in:
Jesse Andrews 2011-08-10 11:55:39 -07:00
commit 2e59567f97
12 changed files with 205 additions and 7 deletions

11
.mailmap Normal file
View File

@ -0,0 +1,11 @@
Antony Messerli <amesserl@rackspace.com> root <root@debian.ohthree.com>
<amesserl@rackspace.com> <root@debian.ohthree.com>
<brian.waldon@rackspace.com> <bcwaldon@gmail.com>
Chris Behrens <cbehrens+github@codestud.com> comstud <cbehrens+github@codestud.com>
<cbehrens+github@codestud.com> <cbehrens@codestud.com>
Johannes Erdfelt <johannes.erdfelt@rackspace.com> jerdfelt <johannes@erdfelt.com>
<johannes.erdfelt@rackspace.com> <johannes@erdfelt.com>
<josh@jk0.org> <jkearney@nova.(none)>
<sandy@darksecretsoftware.com> <sandy.walsh@rackspace.com>
<sandy@darksecretsoftware.com> <sandy@sandywalsh.com>
Andy Smith <github@anarkystic.com> termie <github@anarkystic.com>

View File

@ -1,8 +1,10 @@
Andrey Brindeyev <abrindeyev@griddynamics.com>
Andy Smith <github@anarkystic.com>
Antony Messerli <amesserl@rackspace.com>
Brian Lamar <brian.lamar@rackspace.com>
Brian Waldon <brian.waldon@rackspace.com>
Chris Behrens <cbehrens@codestud.com>
Christopher MacGown <chris@pistoncloud.com>
Chris Behrens <cbehrens+github@codestud.com>
Christopher MacGown <ignoti+github@gmail.com>
Ed Leafe <ed@leafe.com>
Eldar Nugaev <eldr@ya.ru>
Ilya Alekseyev <ilyaalekseyev@acm.org>
@ -12,5 +14,4 @@ Kevin L. Mitchell <kevin.mitchell@rackspace.com>
Kirill Shileev <kshileev@griddynamics.com>
Lvov Maxim <mlvov@mirantis.com>
Matt Dietz <matt.dietz@rackspace.com>
Sandy Walsh <sandy.walsh@rackspace.com>
jerdfelt <johannes@erdfelt.com>
Sandy Walsh <sandy@darksecretsoftware.com>

View File

@ -1,5 +1,5 @@
# Copyright 2010 Jacob Kaplan-Moss
# Copyright 2011 Piston Cloud Computing
# Copyright 2011 Piston Cloud Computing, Inc.
"""
OpenStack Client interface. Handles the REST calls and responses.
@ -141,7 +141,10 @@ class HTTPClient(httplib2.Http):
headers['X-Auth-Project-Id'] = self.projectid
resp, body = self.request(self.auth_url, 'GET', headers=headers)
self.management_url = resp['x-server-management-url']
try:
self.management_url = resp['x-server-management-url']
except KeyError:
raise exceptions.AuthorizationFailure()
self.auth_token = resp['x-auth-token']
else:

View File

@ -8,6 +8,10 @@ class CommandError(Exception):
pass
class AuthorizationFailure(Exception):
pass
class ClientException(Exception):
"""
The base exception class for all exceptions this library raises.

View File

@ -166,6 +166,8 @@ class OpenStackComputeShell(object):
self.cs.authenticate()
except exc.Unauthorized:
raise exc.CommandError("Invalid OpenStack Nova credentials.")
except exc.AuthorizationFailure:
raise exc.CommandError("Unable to authorize user")
args.func(self.cs, args)

View File

@ -3,6 +3,7 @@ from novaclient.v1_1 import flavors
from novaclient.v1_1 import images
from novaclient.v1_1 import keypairs
from novaclient.v1_1 import servers
from novaclient.v1_1 import quotas
from novaclient.v1_1 import zones
@ -32,6 +33,7 @@ class Client(object):
# extensions
self.keypairs = keypairs.KeypairManager(self)
self.zones = zones.ZoneManager(self)
self.quotas = quotas.QuotaSetManager(self)
self.client = client.HTTPClient(username,
api_key,

73
novaclient/v1_1/quotas.py Normal file
View File

@ -0,0 +1,73 @@
# Copyright 2011 OpenStack LLC.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from novaclient import base
class QuotaSet(base.Resource):
def get(self):
self.manager.get(self)
def delete(self):
self.manager.delete(self)
def update(self, *args, **kwargs):
self.manager.update(self.tenant_id, *args, **kwargs)
class QuotaSetManager(base.ManagerWithFind):
resource_class = QuotaSet
def list(self, defaults=False):
if defaults == True:
return self._list('/os-quotas?defaults=True',
'quota_set_list')
else:
return self._list("/os-quotas", "quota_set_list")
def get(self, tenant_id):
if hasattr(tenant_id, 'tenant_id'):
tenant_id = tenant_id.tenant_id
return self._get("/os-quotas/%s" % (tenant_id), "quota_set")
def update(self, tenant_id, metadata_items=None,
injected_file_content_bytes=None, volumes=None, gigabytes=None,
ram=None, floating_ips=None, instances=None, injected_files=None,
cores=None):
body = {'quota_set': {
'tenant_id': tenant_id,
'metadata_items': metadata_items,
'injected_file_content_bytes': injected_file_content_bytes,
'volumes': volumes,
'gigabytes': gigabytes,
'ram': ram,
'floating_ips': floating_ips,
'instances': instances,
'injected_files': injected_files,
'cores': cores,
}}
for key in body['quota_set'].keys():
if body['quota_set'][key] == None:
body['quota_set'].pop(key)
return self._update('/os-quotas/%s' % (tenant_id), body)
def delete(self, tenant_id):
if hasattr(tenant_id, 'tenant_id'):
tenant_id = tenant_id.tenant_id
self._delete("/os-quotas/%s" % (tenant_id))

View File

@ -1,5 +1,4 @@
[nosetests]
with-coverage = true
cover-package = novaclient
cover-html = true
cover-erase = true

View File

@ -2,6 +2,7 @@ import httplib2
import mock
from novaclient import client
from novaclient import exceptions
from tests import utils
@ -54,3 +55,13 @@ class ClientTest(utils.TestCase):
headers=headers, body='[1, 2, 3]')
test_post_call()
def test_auth_failure(self):
cl = get_client()
# response must not have x-server-management-url header
@mock.patch.object(httplib2.Http, "request", mock_request)
def test_auth_call():
self.assertRaises(exceptions.AuthorizationFailure, cl.authenticate)
test_auth_call()

View File

@ -31,8 +31,13 @@ class FakeHTTPClient(base_client.HTTPClient):
assert 'body' in kwargs
# Call the method
<<<<<<< HEAD
munged_url = url.strip('/').replace('/', '_') \
.replace('.', '_').replace('-', '_')
=======
munged_url = url.strip('/').replace('/', '_').replace('.', '_')
munged_url = munged_url.replace('-', '_')
>>>>>>> rax/master
callback = "%s_%s" % (method.lower(), munged_url)
if not hasattr(self, callback):
raise AssertionError('Called unknown API method: %s %s' % (method,
@ -392,3 +397,44 @@ class FakeHTTPClient(base_client.HTTPClient):
required=['name'])
r = {'keypair': self.get_os_keypairs()[1]['keypairs'][0]}
return (202, r)
#
# Quotas
#
def get_os_quotas(self, *kw):
return (200, {'quota_set_list': [{
'tenant_id': 'test',
'metadata_items': [],
'injected_file_content_bytes': 1,
'volumes': 1,
'gigabytes': 1,
'ram': 1,
'floating_ips': 1,
'instances': 1,
'injected_files': 1,
'cores': 1,
}]})
def get_os_quotas_test(self, *kw):
return (200, {'quota_set': {
'tenant_id': 'test',
'metadata_items': [],
'injected_file_content_bytes': 1,
'volumes': 1,
'gigabytes': 1,
'ram': 1,
'floating_ips': 1,
'instances': 1,
'injected_files': 1,
'cores': 1,
}})
def delete_os_quotas_test(self, **kw):
return (202, None)
def put_os_quotas_test(self, body, **kw):
assert body.keys() == ['quota_set']
fakes.assert_has_keys(body['quota_set'],
required=['tenant_id'])
r = self.get_os_quotas_test()[1]
return (200, r)

43
tests/v1_1/test_quotas.py Normal file
View File

@ -0,0 +1,43 @@
# Copyright 2011 OpenStack LLC.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from novaclient import exceptions
from novaclient.v1_1 import quotas
from tests.v1_1 import fakes
from tests import utils
cs = fakes.FakeClient()
class QuoatsTest(utils.TestCase):
def test_list_quotas(self):
qs = cs.quotas.list()
cs.assert_called('GET', '/os-quotas')
[self.assertTrue(isinstance(q, quotas.QuotaSet)) for q in qs]
def test_delete_quota(self):
q = cs.quotas.list()[0]
q.delete()
cs.assert_called('DELETE', '/os-quotas/test')
cs.quotas.delete('test')
cs.assert_called('DELETE', '/os-quotas/test')
cs.quotas.delete(q)
cs.assert_called('DELETE', '/os-quotas/test')
def test_update_quota(self):
q = cs.quotas.list()[0]
q.update(volumes=2)
cs.assert_called('PUT', '/os-quotas/test')

3
tools/generate_authors.sh Executable file
View File

@ -0,0 +1,3 @@
#!/bin/bash
git shortlog -se | cut -c8-