updating server backup action; pep8 fixes
This commit is contained in:
parent
20251ccc2f
commit
ca8aa158fc
|
@ -1,8 +1,10 @@
|
||||||
from novaclient import base
|
from novaclient import base
|
||||||
|
|
||||||
|
|
||||||
class Account(base.Resource):
|
class Account(base.Resource):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class AccountManager(base.BootingManagerWithFind):
|
class AccountManager(base.BootingManagerWithFind):
|
||||||
resource_class = Account
|
resource_class = Account
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ from novaclient import exceptions
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class OpenStackClient(httplib2.Http):
|
class OpenStackClient(httplib2.Http):
|
||||||
|
|
||||||
USER_AGENT = 'python-novaclient/%s' % novaclient.__version__
|
USER_AGENT = 'python-novaclient/%s' % novaclient.__version__
|
||||||
|
@ -54,7 +55,8 @@ class OpenStackClient(httplib2.Http):
|
||||||
string_parts.append(' %s' % element)
|
string_parts.append(' %s' % element)
|
||||||
|
|
||||||
for element in kwargs['headers']:
|
for element in kwargs['headers']:
|
||||||
string_parts.append(' -H "%s: %s"' % (element,kwargs['headers'][element]))
|
header = ' -H "%s: %s"' % (element, kwargs['headers'][element])
|
||||||
|
string_parts.append(header)
|
||||||
|
|
||||||
_logger.debug("REQ: %s\n" % "".join(string_parts))
|
_logger.debug("REQ: %s\n" % "".join(string_parts))
|
||||||
_logger.debug("RESP:%s %s\n", resp, body)
|
_logger.debug("RESP:%s %s\n", resp, body)
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
Exception definitions.
|
Exception definitions.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class OpenStackException(Exception):
|
class OpenStackException(Exception):
|
||||||
"""
|
"""
|
||||||
The base exception class for all exceptions this library raises.
|
The base exception class for all exceptions this library raises.
|
||||||
|
|
|
@ -46,8 +46,7 @@ class ImageManager(base.ManagerWithFind):
|
||||||
detail = "/detail"
|
detail = "/detail"
|
||||||
return self._list("/images%s" % detail, "images")
|
return self._list("/images%s" % detail, "images")
|
||||||
|
|
||||||
|
def create(self, server, name):
|
||||||
def create(self, server, name, image_type=None, backup_type=None, rotation=None):
|
|
||||||
"""
|
"""
|
||||||
Create a new image by snapshotting a running :class:`Server`
|
Create a new image by snapshotting a running :class:`Server`
|
||||||
|
|
||||||
|
@ -55,23 +54,7 @@ class ImageManager(base.ManagerWithFind):
|
||||||
:param server: The :class:`Server` (or its ID) to make a snapshot of.
|
:param server: The :class:`Server` (or its ID) to make a snapshot of.
|
||||||
:rtype: :class:`Image`
|
:rtype: :class:`Image`
|
||||||
"""
|
"""
|
||||||
if image_type is None:
|
data = {"image": {"serverId": base.getid(server), "name": name}}
|
||||||
image_type = "snapshot"
|
|
||||||
|
|
||||||
if image_type not in ("backup", "snapshot"):
|
|
||||||
raise Exception("Invalid image_type: must be backup or snapshot")
|
|
||||||
|
|
||||||
if image_type == "backup":
|
|
||||||
if not rotation:
|
|
||||||
raise Exception("rotation is required for backups")
|
|
||||||
elif not backup_type:
|
|
||||||
raise Exception("backup_type required for backups")
|
|
||||||
elif backup_type not in ("daily", "weekly"):
|
|
||||||
raise Exception("Invalid backup_type: must be daily or weekly")
|
|
||||||
|
|
||||||
data = {"image": {"serverId": base.getid(server), "name": name,
|
|
||||||
"image_type": image_type, "backup_type": backup_type,
|
|
||||||
"rotation": rotation}}
|
|
||||||
return self._create("/images", data, "image")
|
return self._create("/images", data, "image")
|
||||||
|
|
||||||
def delete(self, image):
|
def delete(self, image):
|
||||||
|
|
|
@ -154,6 +154,18 @@ class Server(base.Resource):
|
||||||
"""
|
"""
|
||||||
self.manager.resize(self, flavor)
|
self.manager.resize(self, flavor)
|
||||||
|
|
||||||
|
def backup(self, image_name, backup_type, rotation):
|
||||||
|
"""
|
||||||
|
Create a server backup.
|
||||||
|
|
||||||
|
:param server: The :class:`Server` (or its ID).
|
||||||
|
:param image_name: The name to assign the newly create image.
|
||||||
|
:param backup_type: 'daily' or 'weekly'
|
||||||
|
:param rotation: number of backups of type 'backup_type' to keep
|
||||||
|
:returns Newly created :class:`Image` object
|
||||||
|
"""
|
||||||
|
return self.manager.backup(self, image_name, backup_type, rotation)
|
||||||
|
|
||||||
def confirm_resize(self):
|
def confirm_resize(self):
|
||||||
"""
|
"""
|
||||||
Confirm that the resize worked, thus removing the original server.
|
Confirm that the resize worked, thus removing the original server.
|
||||||
|
@ -370,6 +382,31 @@ class ServerManager(base.BootingManagerWithFind):
|
||||||
"""
|
"""
|
||||||
self._action('resize', server, {'flavorId': base.getid(flavor)})
|
self._action('resize', server, {'flavorId': base.getid(flavor)})
|
||||||
|
|
||||||
|
def backup(self, server, image_name, backup_type, rotation):
|
||||||
|
"""
|
||||||
|
Create a server backup.
|
||||||
|
|
||||||
|
:param server: The :class:`Server` (or its ID).
|
||||||
|
:param image_name: The name to assign the newly create image.
|
||||||
|
:param backup_type: 'daily' or 'weekly'
|
||||||
|
:param rotation: number of backups of type 'backup_type' to keep
|
||||||
|
:returns Newly created :class:`Image` object
|
||||||
|
"""
|
||||||
|
if not rotation:
|
||||||
|
raise Exception("rotation is required for backups")
|
||||||
|
elif not backup_type:
|
||||||
|
raise Exception("backup_type required for backups")
|
||||||
|
elif backup_type not in ("daily", "weekly"):
|
||||||
|
raise Exception("Invalid backup_type: must be daily or weekly")
|
||||||
|
|
||||||
|
data = {
|
||||||
|
"name": image_name,
|
||||||
|
"rotation": rotation,
|
||||||
|
"backup_type": backup_type,
|
||||||
|
}
|
||||||
|
|
||||||
|
self._action('createBackup', server, data)
|
||||||
|
|
||||||
def pause(self, server):
|
def pause(self, server):
|
||||||
"""
|
"""
|
||||||
Pause the server.
|
Pause the server.
|
||||||
|
|
|
@ -481,27 +481,11 @@ class OpenStackShell(object):
|
||||||
print_list(self.cs.images.list(), ['ID', 'Name', 'Status'])
|
print_list(self.cs.images.list(), ['ID', 'Name', 'Status'])
|
||||||
|
|
||||||
@arg('server', metavar='<server>', help='Name or ID of server.')
|
@arg('server', metavar='<server>', help='Name or ID of server.')
|
||||||
@arg('name', metavar='<name>', help='Name of backup or snapshot.')
|
@arg('name', metavar='<name>', help='Name of snapshot.')
|
||||||
@arg('--image-type',
|
|
||||||
metavar='<backup|snapshot>',
|
|
||||||
default='snapshot',
|
|
||||||
help='type of image (default: snapshot)')
|
|
||||||
@arg('--backup-type',
|
|
||||||
metavar='<daily|weekly>',
|
|
||||||
default=None,
|
|
||||||
help='type of backup')
|
|
||||||
@arg('--rotation',
|
|
||||||
default=None,
|
|
||||||
type=int,
|
|
||||||
metavar='<rotation>',
|
|
||||||
help="Number of backups to retain. Used for backup image_type.")
|
|
||||||
def do_image_create(self, args):
|
def do_image_create(self, args):
|
||||||
"""Create a new image by taking a snapshot of a running server."""
|
"""Create a new image by taking a snapshot of a running server."""
|
||||||
server = self._find_server(args.server)
|
server = self._find_server(args.server)
|
||||||
image = self.cs.images.create(server, args.name,
|
image = self.cs.images.create(server, args.name)
|
||||||
image_type=args.image_type,
|
|
||||||
backup_type=args.backup_type,
|
|
||||||
rotation=args.rotation)
|
|
||||||
print_dict(image._info)
|
print_dict(image._info)
|
||||||
|
|
||||||
@arg('image', metavar='<image>', help='Name or ID of image.')
|
@arg('image', metavar='<image>', help='Name or ID of image.')
|
||||||
|
@ -660,6 +644,16 @@ class OpenStackShell(object):
|
||||||
flavor = self._find_flavor(args.flavor)
|
flavor = self._find_flavor(args.flavor)
|
||||||
server.resize(flavor)
|
server.resize(flavor)
|
||||||
|
|
||||||
|
@arg('server', metavar='<server>', help='Name or ID of server.')
|
||||||
|
@arg('name', metavar='<name>', help='Name of snapshot.')
|
||||||
|
@arg('backup_type', metavar='<daily|weekly>', help='type of backup')
|
||||||
|
@arg('rotation', type=int, metavar='<rotation>',
|
||||||
|
help="Number of backups to retain. Used for backup image_type.")
|
||||||
|
def do_backup(self, args):
|
||||||
|
"""Resize a server."""
|
||||||
|
server = self._find_server(args.server)
|
||||||
|
server.backup(args.name, args.backup_type, args.rotation)
|
||||||
|
|
||||||
@arg('server', metavar='<server>', help='Name or ID of server.')
|
@arg('server', metavar='<server>', help='Name or ID of server.')
|
||||||
def do_migrate(self, args):
|
def do_migrate(self, args):
|
||||||
"""Migrate a server."""
|
"""Migrate a server."""
|
||||||
|
|
1
setup.py
1
setup.py
|
@ -2,6 +2,7 @@ import os
|
||||||
import sys
|
import sys
|
||||||
from setuptools import setup, find_packages
|
from setuptools import setup, find_packages
|
||||||
|
|
||||||
|
|
||||||
def read(fname):
|
def read(fname):
|
||||||
return open(os.path.join(os.path.dirname(__file__), fname)).read()
|
return open(os.path.join(os.path.dirname(__file__), fname)).read()
|
||||||
|
|
||||||
|
|
|
@ -267,6 +267,9 @@ class FakeClient(OpenStackClient):
|
||||||
assert_equal(body[action].keys(), ['imageId'])
|
assert_equal(body[action].keys(), ['imageId'])
|
||||||
elif action == 'resize':
|
elif action == 'resize':
|
||||||
assert_equal(body[action].keys(), ['flavorId'])
|
assert_equal(body[action].keys(), ['flavorId'])
|
||||||
|
elif action == 'createBackup':
|
||||||
|
assert_equal(set(body[action].keys()),
|
||||||
|
set(['name', 'rotation', 'backup_type']))
|
||||||
elif action == 'confirmResize':
|
elif action == 'confirmResize':
|
||||||
assert_equal(body[action], None)
|
assert_equal(body[action], None)
|
||||||
# This one method returns a different response code
|
# This one method returns a different response code
|
||||||
|
@ -342,7 +345,7 @@ class FakeClient(OpenStackClient):
|
||||||
|
|
||||||
def post_images(self, body, **kw):
|
def post_images(self, body, **kw):
|
||||||
assert_equal(body.keys(), ['image'])
|
assert_equal(body.keys(), ['image'])
|
||||||
assert_has_keys(body['image'], required=['serverId', 'name', 'image_type', 'backup_type', 'rotation'])
|
assert_has_keys(body['image'], required=['serverId', 'name'])
|
||||||
return (202, self.get_images_1()[1])
|
return (202, self.get_images_1()[1])
|
||||||
|
|
||||||
def delete_images_1(self, **kw):
|
def delete_images_1(self, **kw):
|
||||||
|
@ -409,7 +412,6 @@ class FakeClient(OpenStackClient):
|
||||||
{'id': 2, 'api_url': 'http://foo.com', 'username': 'alice'},
|
{'id': 2, 'api_url': 'http://foo.com', 'username': 'alice'},
|
||||||
]})
|
]})
|
||||||
|
|
||||||
|
|
||||||
def get_zones_detail(self, **kw):
|
def get_zones_detail(self, **kw):
|
||||||
return (200, {'zones': [
|
return (200, {'zones': [
|
||||||
{'id': 1, 'api_url': 'http://foo.com', 'username': 'bob',
|
{'id': 1, 'api_url': 'http://foo.com', 'username': 'bob',
|
||||||
|
|
|
@ -7,6 +7,7 @@ from novaclient import Account
|
||||||
|
|
||||||
cs = FakeServer()
|
cs = FakeServer()
|
||||||
|
|
||||||
|
|
||||||
def test_instance_creation_for_account():
|
def test_instance_creation_for_account():
|
||||||
s = cs.accounts.create_instance_for(
|
s = cs.accounts.create_instance_for(
|
||||||
account_id='test_account',
|
account_id='test_account',
|
||||||
|
|
|
@ -150,6 +150,14 @@ def test_revert_resized_server():
|
||||||
cs.assert_called('POST', '/servers/1234/action')
|
cs.assert_called('POST', '/servers/1234/action')
|
||||||
|
|
||||||
|
|
||||||
|
def test_backup_server():
|
||||||
|
s = cs.servers.get(1234)
|
||||||
|
s.backup("ImageName", "daily", 10)
|
||||||
|
cs.assert_called('POST', '/servers/1234/action')
|
||||||
|
cs.servers.backup(s, "ImageName", "daily", 10)
|
||||||
|
cs.assert_called('POST', '/servers/1234/action')
|
||||||
|
|
||||||
|
|
||||||
def test_migrate_server():
|
def test_migrate_server():
|
||||||
s = cs.servers.get(1234)
|
s = cs.servers.get(1234)
|
||||||
s.migrate()
|
s.migrate()
|
||||||
|
|
|
@ -195,15 +195,7 @@ def test_snapshot_create():
|
||||||
shell('image-create sample-server mysnapshot')
|
shell('image-create sample-server mysnapshot')
|
||||||
assert_called(
|
assert_called(
|
||||||
'POST', '/images',
|
'POST', '/images',
|
||||||
{'image': {'name': 'mysnapshot', 'serverId': 1234, 'image_type': 'snapshot', 'backup_type': None, 'rotation': None}}
|
{'image': {'name': 'mysnapshot', 'serverId': 1234}}
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def test_backup_create():
|
|
||||||
shell('image-create sample-server mybackup --image-type backup --backup-type daily --rotation 1')
|
|
||||||
assert_called(
|
|
||||||
'POST', '/images',
|
|
||||||
{'image': {'name': 'mybackup', 'serverId': 1234, 'image_type': 'backup', 'backup_type': 'daily', 'rotation': 1}}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -295,6 +287,15 @@ def test_resize_revert():
|
||||||
assert_called('POST', '/servers/1234/action', {'revertResize': None})
|
assert_called('POST', '/servers/1234/action', {'revertResize': None})
|
||||||
|
|
||||||
|
|
||||||
|
def test_backup():
|
||||||
|
shell('backup sample-server mybackup daily 1')
|
||||||
|
assert_called(
|
||||||
|
'POST', '/servers/1234/action',
|
||||||
|
{'createBackup': {'name': 'mybackup', 'backup_type': 'daily',
|
||||||
|
'rotation': 1}}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@mock.patch('getpass.getpass', mock.Mock(return_value='p'))
|
@mock.patch('getpass.getpass', mock.Mock(return_value='p'))
|
||||||
def test_root_password():
|
def test_root_password():
|
||||||
shell('root-password sample-server')
|
shell('root-password sample-server')
|
||||||
|
@ -326,6 +327,7 @@ def test_zone():
|
||||||
'password': 'xxx'}}
|
'password': 'xxx'}}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_zone_add():
|
def test_zone_add():
|
||||||
shell('zone-add http://zzz frank xxx 0.0 1.0')
|
shell('zone-add http://zzz frank xxx 0.0 1.0')
|
||||||
assert_called(
|
assert_called(
|
||||||
|
@ -335,6 +337,7 @@ def test_zone_add():
|
||||||
'weight_offset': '0.0', 'weight_scale': '1.0'}}
|
'weight_offset': '0.0', 'weight_scale': '1.0'}}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_zone_delete():
|
def test_zone_delete():
|
||||||
shell('zone-delete 1')
|
shell('zone-delete 1')
|
||||||
assert_called('DELETE', '/zones/1')
|
assert_called('DELETE', '/zones/1')
|
||||||
|
|
Loading…
Reference in New Issue