nova/nova/api/metadata/password.py

89 lines
2.9 KiB
Python

# Copyright 2012 Nebula, Inc.
# 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 webob import exc
import nova.conf
from nova import context
from nova import exception
from nova.i18n import _
from nova import objects
from nova import utils
CONF = nova.conf.CONF
CHUNKS = 4
CHUNK_LENGTH = 255
MAX_SIZE = CHUNKS * CHUNK_LENGTH
def extract_password(instance):
result = ''
sys_meta = utils.instance_sys_meta(instance)
for key in sorted(sys_meta.keys()):
if key.startswith('password_'):
result += sys_meta[key]
return result or None
def convert_password(context, password):
"""Stores password as system_metadata items.
Password is stored with the keys 'password_0' -> 'password_3'.
"""
password = password or ''
if isinstance(password, bytes):
password = password.decode('utf-8')
meta = {}
for i in range(CHUNKS):
meta['password_%d' % i] = password[:CHUNK_LENGTH]
password = password[CHUNK_LENGTH:]
return meta
def handle_password(req, meta_data):
ctxt = context.get_admin_context()
if req.method == 'GET':
return meta_data.password
elif req.method == 'POST':
# NOTE(vish): The conflict will only happen once the metadata cache
# updates, but it isn't a huge issue if it can be set for
# a short window.
if meta_data.password:
raise exc.HTTPConflict()
if (req.content_length > MAX_SIZE or len(req.body) > MAX_SIZE):
msg = _("Request is too large.")
raise exc.HTTPBadRequest(explanation=msg)
if CONF.api.local_metadata_per_cell:
instance = objects.Instance.get_by_uuid(ctxt, meta_data.uuid)
else:
im = objects.InstanceMapping.get_by_instance_uuid(
ctxt, meta_data.uuid)
with context.target_cell(ctxt, im.cell_mapping) as cctxt:
try:
instance = objects.Instance.get_by_uuid(
cctxt, meta_data.uuid)
except exception.InstanceNotFound as e:
raise exc.HTTPBadRequest(explanation=e.format_message())
instance.system_metadata.update(convert_password(ctxt, req.body))
instance.save()
else:
msg = _("GET and POST only are supported.")
raise exc.HTTPBadRequest(explanation=msg)