Fix bug 921814 changes handling of adminPass in API.

Add a new nova configuration flag, boolean, enable_instance_password.

When the flag is True (default), existing behavior is unchanged.

When the flag is False, responses from the create or
rebuild API calls don't include the adminPass attribute.

Change-Id: Icb2bd703770f3a39bb1e458dc31e1489d48da7c1
This commit is contained in:
Mike Pittaro
2012-02-03 15:46:01 -08:00
parent 8f7bc2ee6c
commit 229221ec97
5 changed files with 221 additions and 9 deletions

View File

@@ -115,6 +115,7 @@ Matthew Hooker <matt@cloudscaling.com>
Michael Gundlach <michael.gundlach@rackspace.com>
Michael Still <mikal@stillhq.com>
Mike Lundy <mike@pistoncloud.com>
Mike Pittaro <mikeyp@lahondaresearch.org>
Mike Scherbakov <mihgen@gmail.com>
Mikyung Kang <mkkang@isi.edu>
Mohammed Naser <mnaser@vexxhost.com>

View File

@@ -784,7 +784,8 @@ class Controller(wsgi.Controller):
if '_is_precooked' in server['server'].keys():
del server['server']['_is_precooked']
else:
server['server']['adminPass'] = password
if FLAGS.enable_instance_password:
server['server']['adminPass'] = password
robj = wsgi.ResponseObject(server)
@@ -1107,7 +1108,9 @@ class Controller(wsgi.Controller):
view = self._view_builder.show(req, instance)
# Add on the adminPass attribute since the view doesn't do it
view['server']['adminPass'] = password
# unless instance passwords are disabled
if FLAGS.enable_instance_password:
view['server']['adminPass'] = password
robj = wsgi.ResponseObject(view)
return self._add_location(robj)

View File

@@ -503,6 +503,10 @@ global_opts = [
cfg.BoolOpt('use_ipv6',
default=False,
help='use ipv6'),
cfg.BoolOpt('enable_instance_password',
default=True,
help='Allows use of instance password during '
'server creation'),
cfg.IntOpt('password_length',
default=12,
help='Length of generated instance admin passwords'),

View File

@@ -165,7 +165,8 @@ class ServerActionsControllerTest(test.TestCase):
self.service.delete_all()
self.sent_to_glance = {}
fakes.stub_out_glance_add_image(self.stubs, self.sent_to_glance)
self.flags(allow_instance_snapshots=True)
self.flags(allow_instance_snapshots=True,
enable_instance_password=True)
self.uuid = FAKE_UUID
self.url = '/v2/fake/servers/%s/action' % self.uuid
self._image_href = '155d900f-4e14-4e4c-a73d-069cbf4541e6'
@@ -187,6 +188,22 @@ class ServerActionsControllerTest(test.TestCase):
self.assertEqual(mock_method.instance_id, self.uuid)
self.assertEqual(mock_method.password, '1234pass')
def test_server_change_password_pass_disabled(self):
# run with enable_instance_password disabled to verify adminPass
# is missing from response. See lp bug 921814
self.flags(enable_instance_password=False)
mock_method = MockSetAdminPassword()
self.stubs.Set(nova.compute.api.API, 'set_admin_password', mock_method)
body = {'changePassword': {'adminPass': '1234pass'}}
req = fakes.HTTPRequest.blank(self.url)
self.controller._action_change_password(req, FAKE_UUID, body)
self.assertEqual(mock_method.instance_id, self.uuid)
# note,the mock still contains the password.
self.assertEqual(mock_method.password, '1234pass')
def test_server_change_password_not_a_string(self):
body = {'changePassword': {'adminPass': 1234}}
req = fakes.HTTPRequest.blank(self.url)
@@ -280,6 +297,31 @@ class ServerActionsControllerTest(test.TestCase):
self.assertEqual(body['server']['image']['id'], '2')
self.assertEqual(len(body['server']['adminPass']),
FLAGS.password_length)
self.assertEqual(robj['location'], self_href)
def test_rebuild_accepted_minimum_pass_disabled(self):
# run with enable_instance_password disabled to verify adminPass
# is missing from response. See lp bug 921814
self.flags(enable_instance_password=False)
new_return_server = return_server_with_attributes(image_ref='2')
self.stubs.Set(nova.db, 'instance_get', new_return_server)
self_href = 'http://localhost/v2/fake/servers/%s' % FAKE_UUID
body = {
"rebuild": {
"imageRef": self._image_href,
},
}
req = fakes.HTTPRequest.blank(self.url)
robj = self.controller._action_rebuild(req, FAKE_UUID, body)
body = robj.obj
self.assertEqual(body['server']['image']['id'], '2')
self.assertTrue("adminPass" not in body['server'])
self.assertEqual(robj['location'], self_href)
def test_rebuild_raises_conflict_on_invalid_state(self):
@@ -391,6 +433,27 @@ class ServerActionsControllerTest(test.TestCase):
self.assertEqual(body['server']['image']['id'], '2')
self.assertEqual(body['server']['adminPass'], 'asdf')
def test_rebuild_admin_pass_pass_disabled(self):
# run with enable_instance_password disabled to verify adminPass
# is missing from response. See lp bug 921814
self.flags(enable_instance_password=False)
new_return_server = return_server_with_attributes(image_ref='2')
self.stubs.Set(nova.db, 'instance_get', new_return_server)
body = {
"rebuild": {
"imageRef": self._image_href,
"adminPass": "asdf",
},
}
req = fakes.HTTPRequest.blank(self.url)
body = self.controller._action_rebuild(req, FAKE_UUID, body).obj
self.assertEqual(body['server']['image']['id'], '2')
self.assertTrue('adminPass' not in body['server'])
def test_rebuild_server_not_found(self):
def server_not_found(self, instance_id):
raise exception.InstanceNotFound(instance_id=instance_id)

View File

@@ -1393,7 +1393,8 @@ class ServersControllerCreateTest(test.TestCase):
super(ServersControllerCreateTest, self).setUp()
self.maxDiff = None
self.flags(verbose=True)
self.flags(verbose=True,
enable_instance_password=True)
self.config_drive = None
self.instance_cache_num = 0
self.instance_cache = {}
@@ -1475,6 +1476,20 @@ class ServersControllerCreateTest(test.TestCase):
self.stubs.Set(nova.network.manager.VlanManager, 'allocate_fixed_ip',
fake_method)
def _check_admin_pass_len(self, server_dict):
""" utility function - check server_dict for adminPass
length.
"""
self.assertEqual(FLAGS.password_length,
len(server_dict["adminPass"]))
def _check_admin_pass_missing(self, server_dict):
""" utility function - check server_dict for absence
of adminPass
"""
self.assertTrue("adminPass" not in server_dict)
def _test_create_instance(self):
image_uuid = 'c905cedb-7281-47e4-8a62-f26bc5fc4c77'
body = dict(server=dict(
@@ -1487,7 +1502,7 @@ class ServersControllerCreateTest(test.TestCase):
req.headers["content-type"] = "application/json"
server = self.controller.create(req, body).obj['server']
self.assertEqual(FLAGS.password_length, len(server['adminPass']))
self._check_admin_pass_len(server)
self.assertEqual(FAKE_UUID, server['id'])
def test_create_multiple_instances(self):
@@ -1515,7 +1530,35 @@ class ServersControllerCreateTest(test.TestCase):
res = self.controller.create(req, body).obj
self.assertEqual(FAKE_UUID, res["server"]["id"])
self.assertEqual(12, len(res["server"]["adminPass"]))
self._check_admin_pass_len(res["server"])
def test_create_multiple_instances_pass_disabled(self):
"""Test creating multiple instances but not asking for
reservation_id
"""
self.flags(enable_instance_password=False)
image_href = '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6'
flavor_ref = 'http://localhost/123/flavors/3'
body = {
'server': {
'min_count': 2,
'name': 'server_test',
'imageRef': image_href,
'flavorRef': flavor_ref,
'metadata': {'hello': 'world',
'open': 'stack'},
'personality': []
}
}
req = fakes.HTTPRequest.blank('/v2/fake/servers')
req.method = 'POST'
req.body = json.dumps(body)
req.headers["content-type"] = "application/json"
res = self.controller.create(req, body).obj
self.assertEqual(FAKE_UUID, res["server"]["id"])
self._check_admin_pass_missing(res["server"])
def test_create_multiple_instances_resv_id_return(self):
"""Test creating multiple instances with asking for
@@ -1678,7 +1721,47 @@ class ServersControllerCreateTest(test.TestCase):
res = self.controller.create(req, body).obj
server = res['server']
self.assertEqual(FLAGS.password_length, len(server['adminPass']))
self._check_admin_pass_len(server)
self.assertEqual(FAKE_UUID, server['id'])
def test_create_instance_with_access_ip_pass_disabled(self):
# test with admin passwords disabled See lp bug 921814
self.flags(enable_instance_password=False)
# proper local hrefs must start with 'http://localhost/v2/'
image_uuid = '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6'
image_href = 'http://localhost/v2/fake/images/%s' % image_uuid
flavor_ref = 'http://localhost/fake/flavors/3'
access_ipv4 = '1.2.3.4'
access_ipv6 = 'fead::1234'
body = {
'server': {
'name': 'server_test',
'imageRef': image_href,
'flavorRef': flavor_ref,
'accessIPv4': access_ipv4,
'accessIPv6': access_ipv6,
'metadata': {
'hello': 'world',
'open': 'stack',
},
'personality': [
{
"path": "/etc/banner.txt",
"contents": "MQ==",
},
],
},
}
req = fakes.HTTPRequest.blank('/v2/fake/servers')
req.method = 'POST'
req.body = json.dumps(body)
req.headers["content-type"] = "application/json"
res = self.controller.create(req, body).obj
server = res['server']
self._check_admin_pass_missing(server)
self.assertEqual(FAKE_UUID, server['id'])
def test_create_instance_bad_format_access_ip_v4(self):
@@ -1768,6 +1851,7 @@ class ServersControllerCreateTest(test.TestCase):
"path": "/etc/banner.txt",
"contents": "MQ==",
},
],
},
}
@@ -1779,7 +1863,42 @@ class ServersControllerCreateTest(test.TestCase):
res = self.controller.create(req, body).obj
server = res['server']
self.assertEqual(FLAGS.password_length, len(server['adminPass']))
self._check_admin_pass_len(server)
self.assertEqual(FAKE_UUID, server['id'])
def test_create_instance_pass_disabled(self):
self.flags(enable_instance_password=False)
# proper local hrefs must start with 'http://localhost/v2/'
image_uuid = '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6'
image_href = 'http://localhost/v2/images/%s' % image_uuid
flavor_ref = 'http://localhost/123/flavors/3'
body = {
'server': {
'name': 'server_test',
'imageRef': image_href,
'flavorRef': flavor_ref,
'metadata': {
'hello': 'world',
'open': 'stack',
},
'personality': [
{
"path": "/etc/banner.txt",
"contents": "MQ==",
},
],
},
}
req = fakes.HTTPRequest.blank('/v2/fake/servers')
req.method = 'POST'
req.body = json.dumps(body)
req.headers["content-type"] = "application/json"
res = self.controller.create(req, body).obj
server = res['server']
self._check_admin_pass_missing(server)
self.assertEqual(FAKE_UUID, server['id'])
def test_create_instance_too_much_metadata(self):
@@ -1835,7 +1954,7 @@ class ServersControllerCreateTest(test.TestCase):
res = self.controller.create(req, body).obj
self.assertEqual(FAKE_UUID, res["server"]["id"])
self.assertEqual(12, len(res["server"]["adminPass"]))
self._check_admin_pass_len(res["server"])
def test_create_instance_invalid_flavor_href(self):
image_href = 'http://localhost/v2/images/2'
@@ -2043,6 +2162,28 @@ class ServersControllerCreateTest(test.TestCase):
server = res['server']
self.assertEqual(server['adminPass'], body['server']['adminPass'])
def test_create_instance_admin_pass_pass_disabled(self):
self.flags(enable_instance_password=False)
image_uuid = '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6'
body = {
'server': {
'name': 'server_test',
'imageRef': image_uuid,
'flavorRef': 3,
'adminPass': 'testpass',
},
}
req = fakes.HTTPRequest.blank('/v2/fake/servers')
req.method = 'POST'
req.body = json.dumps(body)
req.headers['content-type'] = "application/json"
res = self.controller.create(req, body).obj
server = res['server']
self.assertTrue('adminPass' in body['server'] )
self.assertTrue('adminPass' not in server)
def test_create_instance_admin_pass_empty(self):
body = {
'server': {