Skip to content

Commit

Permalink
Fix bug 921814 changes handling of adminPass in API.
Browse files Browse the repository at this point in the history
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
  • Loading branch information
lhrc-mikeyp committed Feb 7, 2012
1 parent 8f7bc2e commit 229221e
Show file tree
Hide file tree
Showing 5 changed files with 221 additions and 9 deletions.
1 change: 1 addition & 0 deletions Authors
Expand Up @@ -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>
Expand Down
7 changes: 5 additions & 2 deletions nova/api/openstack/compute/servers.py
Expand Up @@ -784,7 +784,8 @@ def create(self, req, body):
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)

Expand Down Expand Up @@ -1107,7 +1108,9 @@ def _action_rebuild(self, req, id, body):
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)
Expand Down
4 changes: 4 additions & 0 deletions nova/flags.py
Expand Up @@ -503,6 +503,10 @@ def _get_my_ip():
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'),
Expand Down
65 changes: 64 additions & 1 deletion nova/tests/api/openstack/compute/test_server_actions.py
Expand Up @@ -165,7 +165,8 @@ def setUp(self):
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'
Expand All @@ -187,6 +188,22 @@ def test_server_change_password(self):
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)
Expand Down Expand Up @@ -280,6 +297,31 @@ def test_rebuild_accepted_minimum(self):
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):
Expand Down Expand Up @@ -391,6 +433,27 @@ def test_rebuild_admin_pass(self):
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)
Expand Down
153 changes: 147 additions & 6 deletions nova/tests/api/openstack/compute/test_servers.py
Expand Up @@ -1393,7 +1393,8 @@ def setUp(self):
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 = {}
Expand Down Expand Up @@ -1475,6 +1476,20 @@ def queue_get_for(context, *args):
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(
Expand All @@ -1487,7 +1502,7 @@ def _test_create_instance(self):
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):
Expand Down Expand Up @@ -1515,7 +1530,35 @@ def test_create_multiple_instances(self):
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
Expand Down Expand Up @@ -1678,7 +1721,47 @@ def test_create_instance_with_access_ip(self):
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):
Expand Down Expand Up @@ -1768,6 +1851,42 @@ def test_create_instance(self):
"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_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==",
},

],
},
}
Expand All @@ -1779,7 +1898,7 @@ def test_create_instance(self):
res = self.controller.create(req, body).obj

server = res['server']
self.assertEqual(FLAGS.password_length, len(server['adminPass']))
self._check_admin_pass_missing(server)
self.assertEqual(FAKE_UUID, server['id'])

def test_create_instance_too_much_metadata(self):
Expand Down Expand Up @@ -1835,7 +1954,7 @@ def test_create_instance_valid_key_name(self):
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'
Expand Down Expand Up @@ -2043,6 +2162,28 @@ def test_create_instance_admin_pass(self):
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': {
Expand Down

0 comments on commit 229221e

Please sign in to comment.