Browse Source

Re-enable uefi support with glanceclient

Use glanceclient to examine image metadata instead of the nova
image proxy, which seems to have been removed in recent versions of
novaclient.
tags/1.0
Ben Nemec 3 years ago
parent
commit
53320ee72b
7 changed files with 153 additions and 107 deletions
  1. +29
    -0
      openstack_virtual_baremetal/auth.py
  2. +16
    -11
      openstack_virtual_baremetal/build_nodes_json.py
  3. +1
    -29
      openstack_virtual_baremetal/deploy.py
  4. +54
    -0
      openstack_virtual_baremetal/tests/test_auth.py
  5. +49
    -16
      openstack_virtual_baremetal/tests/test_build_nodes_json.py
  6. +3
    -51
      openstack_virtual_baremetal/tests/test_deploy.py
  7. +1
    -0
      requirements.txt

+ 29
- 0
openstack_virtual_baremetal/auth.py View File

@@ -127,3 +127,32 @@ def _get_keystone_token():
project_domain_name=project_domain)


def _get_token_and_endpoint(name):
"""Return a token id and endpoint url for the specified service

:param name: The name of the service. heat, glance, etc.
:returns: A tuple of (token_id, service_endpoint)
"""
auth_data = _create_auth_parameters()
auth_url = auth_data['os_auth_url']
# Get token for service to use
if '/v3' not in auth_url:
token_data = _get_keystone_token()
token_id = token_data['token']['id']
catalog_key = 'serviceCatalog'
else:
token_data = _get_keystone_token()
token_id = token_data['auth_token']
catalog_key = 'catalog'

# Get service endpoint
for endpoint in token_data[catalog_key]:
if endpoint['name'] == name:
try:
# TODO: What if there's more than one endpoint?
service_endpoint = endpoint['endpoints'][0]['publicURL']
except KeyError:
# Keystone v3 endpoint data looks different
service_endpoint = [e for e in endpoint['endpoints']
if e['interface'] == 'public'][0]['url']
return token_id, service_endpoint

+ 16
- 11
openstack_virtual_baremetal/build_nodes_json.py View File

@@ -19,6 +19,7 @@ import os
import sys
import yaml

import glanceclient
from neutronclient.v2_0 import client as neutronclient
import novaclient as nc
from novaclient import client as novaclient
@@ -91,6 +92,7 @@ def _get_clients():
import os_client_config
nova = os_client_config.make_client('compute', cloud=cloud)
neutron = os_client_config.make_client('network', cloud=cloud)
glance = os_client_config.make_client('image', cloud=cloud)

else:
auth_data = auth._create_auth_parameters()
@@ -124,7 +126,10 @@ def _get_clients():
project_domain_name=project_domain)
sess = auth._get_keystone_session(auth_data)
neutron = neutronclient.Client(session=sess)
return nova, neutron
token, glance_endpoint = auth._get_token_and_endpoint('glance')
glance = glanceclient.Client('2', token=token,
endpoint=glance_endpoint)
return nova, neutron, glance


def _get_ports(neutron, bmc_base, baremetal_base):
@@ -140,8 +145,8 @@ def _get_ports(neutron, bmc_base, baremetal_base):
return bmc_ports, bm_ports


def _build_nodes(nova, bmc_ports, bm_ports, provision_net, baremetal_base,
undercloud_name):
def _build_nodes(nova, glance, bmc_ports, bm_ports, provision_net,
baremetal_base, undercloud_name):
node_template = {
'pm_type': 'pxe_ipmitool',
'mac': '',
@@ -177,12 +182,11 @@ def _build_nodes(nova, bmc_ports, bm_ports, provision_net, baremetal_base,

# If a node has uefi firmware ironic needs to be aware of this, in nova
# this is set using a image property called "hw_firmware_type"
# TODO(bnemec): Re-enable uefi support
#if not cache.get(baremetal.image['id']):
#cache[baremetal.image['id']] = nova.images.get(baremetal.image['id'])
#image = cache.get(baremetal.image['id'])
#if image.metadata.get('hw_firmware_type') == 'uefi':
#node['capabilities'] += ",boot_mode:uefi"
if not cache.get(baremetal.image['id']):
cache[baremetal.image['id']] = glance.images.get(baremetal.image['id'])
image = cache.get(baremetal.image['id'])
if image.get('hw_firmware_type') == 'uefi':
node['capabilities'] += ",boot_mode:uefi"

bm_name_end = baremetal.name[len(baremetal_base):]
if '-' in bm_name_end:
@@ -240,9 +244,10 @@ def _write_pairs(bmc_bm_pairs):
def main():
args = _parse_args()
bmc_base, baremetal_base, provision_net, undercloud_name = _get_names(args)
nova, neutron = _get_clients()
nova, neutron, glance = _get_clients()
bmc_ports, bm_ports = _get_ports(neutron, bmc_base, baremetal_base)
nodes, bmc_bm_pairs, extra_nodes = _build_nodes(nova, bmc_ports, bm_ports,
nodes, bmc_bm_pairs, extra_nodes = _build_nodes(nova, glance, bmc_ports,
bm_ports,
provision_net,
baremetal_base,
undercloud_name)


+ 1
- 29
openstack_virtual_baremetal/deploy.py View File

@@ -140,35 +140,7 @@ def _get_heat_client():
import os_client_config
return os_client_config.make_client('orchestration', cloud=cloud)
else:
auth_data = auth._create_auth_parameters()
username = auth_data['os_user']
password = auth_data['os_password']
tenant = auth_data['os_tenant']
auth_url = auth_data['os_auth_url']
project = auth_data['os_project']
user_domain = auth_data['os_user_domain']
project_domain = auth_data['os_project_domain']
# Get token for Heat to use
if '/v3' not in auth_url:
token_data = auth._get_keystone_token()
token_id = token_data['token']['id']
catalog_key = 'serviceCatalog'
else:
token_data = auth._get_keystone_token()
token_id = token_data['auth_token']
catalog_key = 'catalog'

# Get Heat endpoint
for endpoint in token_data[catalog_key]:
if endpoint['name'] == 'heat':
try:
# TODO: What if there's more than one endpoint?
heat_endpoint = endpoint['endpoints'][0]['publicURL']
except KeyError:
# Keystone v3 endpoint data looks different
heat_endpoint = [e for e in endpoint['endpoints']
if e['interface'] == 'public'][0]['url']

token_id, heat_endpoint = auth._get_token_and_endpoint('heat')
return heat_client.Client('1', endpoint=heat_endpoint, token=token_id)

def _deploy(stack_name, stack_template, env_path, poll):


+ 54
- 0
openstack_virtual_baremetal/tests/test_auth.py View File

@@ -190,6 +190,26 @@ class TestCreateAuthParameters(testtools.TestCase):
self.assertEqual(expected, result)


V2_TOKEN_DATA = {'token': {'id': 'fake_token'},
'serviceCatalog': [{'name': 'nova'},
{'name': 'heat',
'endpoints': [
{'publicURL': 'heat_endpoint'}
]
}
]}
V3_TOKEN_DATA = {'auth_token': 'fake_v3_token',
'catalog': [{'name': 'nova'},
{'name': 'heat',
'endpoints': [
{'interface': 'private'},
{'interface': 'public',
'url': 'heat_endpoint'}
]
}
]}


class TestKeystoneAuth(testtools.TestCase):
@mock.patch('keystoneauth1.session.Session')
@mock.patch('keystoneauth1.identity.v3.Password')
@@ -289,3 +309,37 @@ class TestKeystoneAuth(testtools.TestCase):
user_domain_name='default',
project_domain_name='default'
)

@mock.patch('openstack_virtual_baremetal.auth._get_keystone_token')
@mock.patch('openstack_virtual_baremetal.auth._create_auth_parameters')
def test_get_token_and_endpoint_v2(self, mock_cap, mock_gkt):
fake_auth_data = {'os_user': 'admin',
'os_password': 'password',
'os_tenant': 'admin',
'os_auth_url': 'auth',
'os_project': '',
'os_user_domain': '',
'os_project_domain': '',
}
mock_cap.return_value = fake_auth_data
mock_gkt.return_value = V2_TOKEN_DATA
token, endpoint = auth._get_token_and_endpoint('heat')
self.assertEqual('fake_token', token)
self.assertEqual('heat_endpoint', endpoint)

@mock.patch('openstack_virtual_baremetal.auth._get_keystone_token')
@mock.patch('openstack_virtual_baremetal.auth._create_auth_parameters')
def test_get_token_and_endpoint_v3(self, mock_cap, mock_gkt):
fake_auth_data = {'os_user': 'admin',
'os_password': 'password',
'os_tenant': '',
'os_auth_url': 'auth/v3',
'os_project': 'admin',
'os_user_domain': 'default',
'os_project_domain': 'default',
}
mock_cap.return_value = fake_auth_data
mock_gkt.return_value = V3_TOKEN_DATA
token, endpoint = auth._get_token_and_endpoint('heat')
self.assertEqual('fake_v3_token', token)
self.assertEqual('heat_endpoint', endpoint)

+ 49
- 16
openstack_virtual_baremetal/tests/test_build_nodes_json.py View File

@@ -161,10 +161,12 @@ class TestBuildNodesJson(testtools.TestCase):
self.useFixture(fixtures.EnvironmentVariable('OS_CLOUD', 'foo'))
build_nodes_json._get_clients()
calls = [mock.call('compute', cloud='foo'),
mock.call('network', cloud='foo')]
mock.call('network', cloud='foo'),
mock.call('image', cloud='foo')]
self.assertEqual(calls, mock_make_client.mock_calls)

def _test_get_clients_env(self, mock_nova, mock_neutron):
def _test_get_clients_env(self, mock_nova, mock_neutron, mock_glance,
mock_gtae):
self.useFixture(fixtures.EnvironmentVariable('OS_USERNAME', 'admin'))
self.useFixture(fixtures.EnvironmentVariable('OS_PASSWORD', 'pw'))
self.useFixture(fixtures.EnvironmentVariable('OS_TENANT_NAME',
@@ -174,28 +176,45 @@ class TestBuildNodesJson(testtools.TestCase):
mock_nova.return_value = mock_nova_client
mock_neutron_client = mock.Mock()
mock_neutron.return_value = mock_neutron_client
nova, neutron = build_nodes_json._get_clients()
mock_glance_client = mock.Mock()
mock_glance.return_value = mock_glance_client
mock_token = 'abc-123'
mock_endpoint = 'glance://endpoint'
mock_gtae.return_value = (mock_token, mock_endpoint)
nova, neutron, glance = build_nodes_json._get_clients()
self.assertEqual(mock_nova_client, nova)
self.assertEqual(mock_neutron_client, neutron)
self.assertEqual(mock_glance_client, glance)

@mock.patch('openstack_virtual_baremetal.auth._get_token_and_endpoint')
@mock.patch('openstack_virtual_baremetal.build_nodes_json.nc.__version__',
('6', '0', '0'))
@mock.patch('glanceclient.Client')
@mock.patch('neutronclient.v2_0.client.Client')
@mock.patch('novaclient.client.Client')
def test_get_clients_env_6(self, mock_nova, mock_neutron):
self._test_get_clients_env(mock_nova, mock_neutron)
def test_get_clients_env_6(self, mock_nova, mock_neutron, mock_glance,
mock_gtae):
self._test_get_clients_env(mock_nova, mock_neutron, mock_glance,
mock_gtae)

@mock.patch('openstack_virtual_baremetal.auth._get_token_and_endpoint')
@mock.patch('openstack_virtual_baremetal.build_nodes_json.nc.__version__',
('7', '0', '0'))
@mock.patch('glanceclient.Client')
@mock.patch('neutronclient.v2_0.client.Client')
@mock.patch('novaclient.client.Client')
def test_get_clients_env_7(self, mock_nova, mock_neutron):
self._test_get_clients_env(mock_nova, mock_neutron)
def test_get_clients_env_7(self, mock_nova, mock_neutron, mock_glance,
mock_gtae):
self._test_get_clients_env(mock_nova, mock_neutron, mock_glance,
mock_gtae)

@mock.patch('openstack_virtual_baremetal.auth._get_token_and_endpoint')
@mock.patch('openstack_virtual_baremetal.auth._get_keystone_session')
@mock.patch('glanceclient.Client')
@mock.patch('neutronclient.v2_0.client.Client')
@mock.patch('novaclient.client.Client')
def test_get_clients_env_v3(self, mock_nova, mock_neutron, mock_gks):
def test_get_clients_env_v3(self, mock_nova, mock_neutron, mock_glance,
mock_gks, mock_gtae):
self.useFixture(fixtures.EnvironmentVariable('OS_USERNAME', 'admin'))
self.useFixture(fixtures.EnvironmentVariable('OS_PASSWORD', 'pw'))
self.useFixture(fixtures.EnvironmentVariable('OS_PROJECT_NAME',
@@ -209,12 +228,20 @@ class TestBuildNodesJson(testtools.TestCase):
mock_nova.return_value = mock_nova_client
mock_neutron_client = mock.Mock()
mock_neutron.return_value = mock_neutron_client
mock_glance_client = mock.Mock()
mock_glance.return_value = mock_glance_client
mock_session_inst = mock.Mock()
mock_gks.return_value = mock_session_inst
nova, neutron = build_nodes_json._get_clients()
mock_token = 'abc-123'
mock_endpoint = 'glance://endpoint'
mock_gtae.return_value = (mock_token, mock_endpoint)
nova, neutron, glance = build_nodes_json._get_clients()
mock_neutron.assert_called_once_with(session=mock_session_inst)
mock_glance.assert_called_once_with('2', token=mock_token,
endpoint=mock_endpoint)
self.assertEqual(mock_nova_client, nova)
self.assertEqual(mock_neutron_client, neutron)
self.assertEqual(mock_glance_client, glance)

def test_get_ports(self):
neutron = mock.Mock()
@@ -296,8 +323,10 @@ class TestBuildNodesJson(testtools.TestCase):
ips_return_val = 'ips call value'
nova.servers.ips.return_value = ips_return_val

glance = mock.Mock()

nodes, bmc_bm_pairs, extra_nodes = build_nodes_json._build_nodes(
nova, bmc_ports, bm_ports, 'provision', 'bm', 'undercloud')
nova, glance, bmc_ports, bm_ports, 'provision', 'bm', 'undercloud')
expected_nodes = TEST_NODES
self.assertEqual(expected_nodes, nodes)
self.assertEqual([('1.1.1.1', 'bm_0'), ('1.1.1.2', 'bm_1')],
@@ -317,12 +346,14 @@ class TestBuildNodesJson(testtools.TestCase):
servers[1].name = 'bm-foo-control_1'
ips_return_val = 'ips call value'
nova.servers.ips.return_value = ips_return_val

glance = mock.Mock()
mock_image_get = mock.Mock()
nova.images.get.return_value = mock_image_get
mock_image_get.metadata.get.return_value = 'uefi'
mock_image_get.get.return_value = 'uefi'
glance.images.get.return_value = mock_image_get

nodes, bmc_bm_pairs, extra_nodes = build_nodes_json._build_nodes(
nova, bmc_ports, bm_ports, 'provision', 'bm-foo', None)
nova, glance, bmc_ports, bm_ports, 'provision', 'bm-foo', None)
expected_nodes = copy.deepcopy(TEST_NODES)
expected_nodes[0]['name'] = 'bm-foo-control-0'
expected_nodes[0]['capabilities'] = ('boot_option:local,'
@@ -396,7 +427,8 @@ class TestBuildNodesJson(testtools.TestCase):
undercloud_name)
nova = mock.Mock()
neutron = mock.Mock()
mock_get_clients.return_value = (nova, neutron)
glance = mock.Mock()
mock_get_clients.return_value = (nova, neutron, glance)
bmc_ports = mock.Mock()
bm_ports = mock.Mock()
mock_get_ports.return_value = (bmc_ports, bm_ports)
@@ -412,8 +444,9 @@ class TestBuildNodesJson(testtools.TestCase):
mock_get_clients.assert_called_once_with()
mock_get_ports.assert_called_once_with(neutron, bmc_base,
baremetal_base)
mock_build_nodes.assert_called_once_with(nova, bmc_ports, bm_ports,
provision_net, baremetal_base,
mock_build_nodes.assert_called_once_with(nova, glance, bmc_ports,
bm_ports, provision_net,
baremetal_base,
undercloud_name)
mock_write_nodes.assert_called_once_with(nodes, extra_nodes, args)
mock_write_pairs.assert_called_once_with(pairs)


+ 3
- 51
openstack_virtual_baremetal/tests/test_deploy.py View File

@@ -371,26 +371,6 @@ class TestDeploy(testtools.TestCase):
deploy._validate_env(args, 'foo.yaml')


V2_TOKEN_DATA = {'token': {'id': 'fake_token'},
'serviceCatalog': [{'name': 'nova'},
{'name': 'heat',
'endpoints': [
{'publicURL': 'heat_endpoint'}
]
}
]}
V3_TOKEN_DATA = {'auth_token': 'fake_v3_token',
'catalog': [{'name': 'nova'},
{'name': 'heat',
'endpoints': [
{'interface': 'private'},
{'interface': 'public',
'url': 'heat_endpoint'}
]
}
]}


class TestGetHeatClient(testtools.TestCase):
@mock.patch('os_client_config.make_client')
def test_os_cloud(self, mock_make_client):
@@ -399,41 +379,13 @@ class TestGetHeatClient(testtools.TestCase):
mock_make_client.assert_called_once_with('orchestration', cloud='foo')

@mock.patch('heatclient.client.Client')
@mock.patch('openstack_virtual_baremetal.auth._get_keystone_token')
@mock.patch('openstack_virtual_baremetal.auth._create_auth_parameters')
def test_keystone_v2(self, mock_cap, mock_gkt, mock_hc):
fake_auth_data = {'os_user': 'admin',
'os_password': 'password',
'os_tenant': 'admin',
'os_auth_url': 'auth',
'os_project': '',
'os_user_domain': '',
'os_project_domain': '',
}
mock_cap.return_value = fake_auth_data
mock_gkt.return_value = V2_TOKEN_DATA
@mock.patch('openstack_virtual_baremetal.auth._get_token_and_endpoint')
def test_heatclient(self, mock_gtae, mock_hc):
mock_gtae.return_value = ('fake_token', 'heat_endpoint')
deploy._get_heat_client()
mock_hc.assert_called_once_with('1', endpoint='heat_endpoint',
token='fake_token')

@mock.patch('heatclient.client.Client')
@mock.patch('openstack_virtual_baremetal.auth._get_keystone_token')
@mock.patch('openstack_virtual_baremetal.auth._create_auth_parameters')
def test_keystone_v3(self, mock_cap, mock_gkt, mock_hc):
fake_auth_data = {'os_user': 'admin',
'os_password': 'password',
'os_tenant': 'admin',
'os_auth_url': 'auth/v3',
'os_project': 'admin',
'os_user_domain': 'default',
'os_project_domain': 'default',
}
mock_cap.return_value = fake_auth_data
mock_gkt.return_value = V3_TOKEN_DATA
deploy._get_heat_client()
mock_hc.assert_called_once_with('1', endpoint='heat_endpoint',
token='fake_v3_token')


if __name__ == '__main__':
unittest.main()

+ 1
- 0
requirements.txt View File

@@ -1,6 +1,7 @@
os-client-config
pyghmi
PyYAML
python-glanceclient
python-heatclient
python-keystoneclient
python-neutronclient


Loading…
Cancel
Save