Merge "Merge v1_1's base module into main base module"

This commit is contained in:
Jenkins 2013-07-30 17:55:26 +00:00 committed by Gerrit Code Review
commit 95e7d70266
3 changed files with 88 additions and 174 deletions

View File

@ -20,6 +20,7 @@ Base utilities to build API operation managers and objects on top of.
""" """
import abc import abc
import base64
import contextlib import contextlib
import hashlib import hashlib
import inspect import inspect
@ -28,6 +29,7 @@ import os
import six import six
from novaclient import exceptions from novaclient import exceptions
from novaclient.openstack.common import strutils
from novaclient import utils from novaclient import utils
@ -224,16 +226,18 @@ class ManagerWithFind(Manager):
class BootingManagerWithFind(ManagerWithFind): class BootingManagerWithFind(ManagerWithFind):
"""Like a `ManagerWithFind`, but has the ability to boot servers.""" """Like a `ManagerWithFind`, but has the ability to boot servers."""
def _boot(self, resource_url, response_key, name, image, flavor, def _boot(self, resource_url, response_key, name, image, flavor,
ipgroup=None, meta=None, files=None, meta=None, files=None, userdata=None,
reservation_id=None, return_raw=False, min_count=None, reservation_id=None, return_raw=False, min_count=None,
max_count=None, **kwargs): max_count=None, security_groups=None, key_name=None,
availability_zone=None, block_device_mapping=None, nics=None,
scheduler_hints=None, config_drive=None, admin_pass=None,
**kwargs):
""" """
Create (boot) a new server. Create (boot) a new server.
:param name: Something to name the server. :param name: Something to name the server.
:param image: The :class:`Image` to boot with. :param image: The :class:`Image` to boot with.
:param flavor: The :class:`Flavor` to boot onto. :param flavor: The :class:`Flavor` to boot onto.
:param ipgroup: An initial :class:`IPGroup` for this server.
:param meta: A dict of arbitrary key/value metadata to store for this :param meta: A dict of arbitrary key/value metadata to store for this
server. A maximum of five entries is allowed, and both server. A maximum of five entries is allowed, and both
keys and values must be 255 characters or less. keys and values must be 255 characters or less.
@ -245,19 +249,45 @@ class BootingManagerWithFind(ManagerWithFind):
:param reservation_id: a UUID for the set of servers being requested. :param reservation_id: a UUID for the set of servers being requested.
:param return_raw: If True, don't try to coearse the result into :param return_raw: If True, don't try to coearse the result into
a Resource object. a Resource object.
:param security_groups: list of security group names
:param key_name: (optional extension) name of keypair to inject into
the instance
:param availability_zone: Name of the availability zone for instance
placement.
:param block_device_mapping: A dict of block device mappings for this
server.
:param nics: (optional extension) an ordered list of nics to be
added to this server, with information about
connected networks, fixed ips, etc.
:param scheduler_hints: (optional extension) arbitrary key-value pairs
specified by the client to help boot an instance.
:param config_drive: (optional extension) value for config drive
either boolean, or volume-id
:param admin_pass: admin password for the server.
""" """
body = {"server": { body = {"server": {
"name": name, "name": name,
"imageId": getid(image), "imageRef": str(getid(image)) if image else '',
"flavorId": getid(flavor), "flavorRef": str(getid(flavor)),
}} }}
if ipgroup: if userdata:
body["server"]["sharedIpGroupId"] = getid(ipgroup) if hasattr(userdata, 'read'):
userdata = userdata.read()
userdata = strutils.safe_encode(userdata)
body["server"]["user_data"] = base64.b64encode(userdata)
if meta: if meta:
body["server"]["metadata"] = meta body["server"]["metadata"] = meta
if reservation_id: if reservation_id:
body["server"]["reservation_id"] = reservation_id body["server"]["reservation_id"] = reservation_id
if key_name:
body["server"]["key_name"] = key_name
if scheduler_hints:
body['os:scheduler_hints'] = scheduler_hints
if config_drive:
body["server"]["config_drive"] = config_drive
if admin_pass:
body["server"]["adminPass"] = admin_pass
if not min_count: if not min_count:
min_count = 1 min_count = 1
if not max_count: if not max_count:
@ -265,6 +295,10 @@ class BootingManagerWithFind(ManagerWithFind):
body["server"]["min_count"] = min_count body["server"]["min_count"] = min_count
body["server"]["max_count"] = max_count body["server"]["max_count"] = max_count
if security_groups:
body["server"]["security_groups"] =\
[{'name': sg} for sg in security_groups]
# Files are a slight bit tricky. They're passed in a "personality" # Files are a slight bit tricky. They're passed in a "personality"
# list to the POST. Each item is a dict giving a file name and the # list to the POST. Each item is a dict giving a file name and the
# base64-encoded contents of the file. We want to allow passing # base64-encoded contents of the file. We want to allow passing
@ -281,6 +315,51 @@ class BootingManagerWithFind(ManagerWithFind):
'contents': data.encode('base64'), 'contents': data.encode('base64'),
}) })
if availability_zone:
body["server"]["availability_zone"] = availability_zone
# Block device mappings are passed as a list of dictionaries
if block_device_mapping:
bdm = body['server']['block_device_mapping'] = []
for device_name, mapping in block_device_mapping.items():
#
# The mapping is in the format:
# <id>:[<type>]:[<size(GB)>]:[<delete_on_terminate>]
#
bdm_dict = {'device_name': device_name}
mapping_parts = mapping.split(':')
id = mapping_parts[0]
if len(mapping_parts) == 1:
bdm_dict['volume_id'] = id
if len(mapping_parts) > 1:
type = mapping_parts[1]
if type.startswith('snap'):
bdm_dict['snapshot_id'] = id
else:
bdm_dict['volume_id'] = id
if len(mapping_parts) > 2:
if mapping_parts[2]:
bdm_dict['volume_size'] = str(int(mapping_parts[2]))
if len(mapping_parts) > 3:
bdm_dict['delete_on_termination'] = mapping_parts[3]
bdm.append(bdm_dict)
if nics is not None:
# NOTE(tr3buchet): nics can be an empty list
all_net_data = []
for nic_info in nics:
net_data = {}
# if value is empty string, do not send value in body
if nic_info.get('net-id'):
net_data['uuid'] = nic_info['net-id']
if nic_info.get('v4-fixed-ip'):
net_data['fixed_ip'] = nic_info['v4-fixed-ip']
if nic_info.get('port-id'):
net_data['port'] = nic_info['port-id']
all_net_data.append(net_data)
body['server']['networks'] = all_net_data
return self._create(resource_url, body, response_key, return self._create(resource_url, body, response_key,
return_raw=return_raw, **kwargs) return_raw=return_raw, **kwargs)

View File

@ -1,164 +0,0 @@
# Copyright 2010 Jacob Kaplan-Moss
# Copyright 2011 OpenStack Foundation
# 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.
import base64
from novaclient import base
from novaclient.openstack.common import strutils
# FIXME(sirp): Now that v1_0 has been removed, this can be merged with
# base.ManagerWithFind
class BootingManagerWithFind(base.ManagerWithFind):
"""Like a `ManagerWithFind`, but has the ability to boot servers."""
def _boot(self, resource_url, response_key, name, image, flavor,
meta=None, files=None, userdata=None,
reservation_id=None, return_raw=False, min_count=None,
max_count=None, security_groups=None, key_name=None,
availability_zone=None, block_device_mapping=None, nics=None,
scheduler_hints=None, config_drive=None, admin_pass=None,
**kwargs):
"""
Create (boot) a new server.
:param name: Something to name the server.
:param image: The :class:`Image` to boot with.
:param flavor: The :class:`Flavor` to boot onto.
:param meta: A dict of arbitrary key/value metadata to store for this
server. A maximum of five entries is allowed, and both
keys and values must be 255 characters or less.
:param files: A dict of files to overrwrite on the server upon boot.
Keys are file names (i.e. ``/etc/passwd``) and values
are the file contents (either as a string or as a
file-like object). A maximum of five entries is allowed,
and each file must be 10k or less.
:param reservation_id: a UUID for the set of servers being requested.
:param return_raw: If True, don't try to coearse the result into
a Resource object.
:param security_groups: list of security group names
:param key_name: (optional extension) name of keypair to inject into
the instance
:param availability_zone: Name of the availability zone for instance
placement.
:param block_device_mapping: A dict of block device mappings for this
server.
:param nics: (optional extension) an ordered list of nics to be
added to this server, with information about
connected networks, fixed ips, etc.
:param scheduler_hints: (optional extension) arbitrary key-value pairs
specified by the client to help boot an instance.
:param config_drive: (optional extension) value for config drive
either boolean, or volume-id
:param admin_pass: admin password for the server.
"""
body = {"server": {
"name": name,
"imageRef": str(base.getid(image)) if image else '',
"flavorRef": str(base.getid(flavor)),
}}
if userdata:
if hasattr(userdata, 'read'):
userdata = userdata.read()
userdata = strutils.safe_encode(userdata)
body["server"]["user_data"] = base64.b64encode(userdata)
if meta:
body["server"]["metadata"] = meta
if reservation_id:
body["server"]["reservation_id"] = reservation_id
if key_name:
body["server"]["key_name"] = key_name
if scheduler_hints:
body['os:scheduler_hints'] = scheduler_hints
if config_drive:
body["server"]["config_drive"] = config_drive
if admin_pass:
body["server"]["adminPass"] = admin_pass
if not min_count:
min_count = 1
if not max_count:
max_count = min_count
body["server"]["min_count"] = min_count
body["server"]["max_count"] = max_count
if security_groups:
body["server"]["security_groups"] =\
[{'name': sg} for sg in security_groups]
# Files are a slight bit tricky. They're passed in a "personality"
# list to the POST. Each item is a dict giving a file name and the
# base64-encoded contents of the file. We want to allow passing
# either an open file *or* some contents as files here.
if files:
personality = body['server']['personality'] = []
for filepath, file_or_string in files.items():
if hasattr(file_or_string, 'read'):
data = file_or_string.read()
else:
data = file_or_string
personality.append({
'path': filepath,
'contents': data.encode('base64'),
})
if availability_zone:
body["server"]["availability_zone"] = availability_zone
# Block device mappings are passed as a list of dictionaries
if block_device_mapping:
bdm = body['server']['block_device_mapping'] = []
for device_name, mapping in block_device_mapping.items():
#
# The mapping is in the format:
# <id>:[<type>]:[<size(GB)>]:[<delete_on_terminate>]
#
bdm_dict = {'device_name': device_name}
mapping_parts = mapping.split(':')
id = mapping_parts[0]
if len(mapping_parts) == 1:
bdm_dict['volume_id'] = id
if len(mapping_parts) > 1:
type = mapping_parts[1]
if type.startswith('snap'):
bdm_dict['snapshot_id'] = id
else:
bdm_dict['volume_id'] = id
if len(mapping_parts) > 2:
if mapping_parts[2]:
bdm_dict['volume_size'] = str(int(mapping_parts[2]))
if len(mapping_parts) > 3:
bdm_dict['delete_on_termination'] = mapping_parts[3]
bdm.append(bdm_dict)
if nics is not None:
# NOTE(tr3buchet): nics can be an empty list
all_net_data = []
for nic_info in nics:
net_data = {}
# if value is empty string, do not send value in body
if nic_info.get('net-id'):
net_data['uuid'] = nic_info['net-id']
if nic_info.get('v4-fixed-ip'):
net_data['fixed_ip'] = nic_info['v4-fixed-ip']
if nic_info.get('port-id'):
net_data['port'] = nic_info['port-id']
all_net_data.append(net_data)
body['server']['networks'] = all_net_data
return self._create(resource_url, body, response_key,
return_raw=return_raw, **kwargs)

View File

@ -25,7 +25,6 @@ import six
from novaclient import base from novaclient import base
from novaclient import crypto from novaclient import crypto
from novaclient.v1_1 import base as local_base
REBOOT_SOFT, REBOOT_HARD = 'SOFT', 'HARD' REBOOT_SOFT, REBOOT_HARD = 'SOFT', 'HARD'
@ -353,7 +352,7 @@ class Server(base.Resource):
return self.manager.interface_detach(self, port_id) return self.manager.interface_detach(self, port_id)
class ServerManager(local_base.BootingManagerWithFind): class ServerManager(base.BootingManagerWithFind):
resource_class = Server resource_class = Server
def get(self, server): def get(self, server):