Make bmc caching configurable

In ci we want to enable caching of instance status to reduce load
on the host cloud, but for interactive developer setups it can be
confusing.  If a user shuts off a baremetal vm without using the
BMC then the BMC won't recognize that its state has changed.

This change makes caching configurable, and disabled by default.
In CI we can enable it explicitly and regular users won't get any
confusing behavior by default.
This commit is contained in:
Ben Nemec 2017-04-27 12:18:07 -05:00
parent 53320ee72b
commit c788a845c4
4 changed files with 53 additions and 10 deletions

View File

@ -57,6 +57,10 @@ export OS_PROJECT_DOMAIN_ID=$os__project_domain
private_subnet=$(neutron net-show -f value -c subnets $private_net | sed "s/\[u'\(.*\)'\]/\1/") private_subnet=$(neutron net-show -f value -c subnets $private_net | sed "s/\[u'\(.*\)'\]/\1/")
default_gw=$(neutron subnet-show $private_subnet -f value -c gateway_ip) default_gw=$(neutron subnet-show $private_subnet -f value -c gateway_ip)
prefix_len=$(neutron subnet-show -f value -c cidr $private_subnet | awk -F / '{print $2}') prefix_len=$(neutron subnet-show -f value -c cidr $private_subnet | awk -F / '{print $2}')
cache_status=
if [ "$bmc_use_cache" != "False" ]; then
cache_status="--cache-status"
fi
mkdir /etc/os-net-config mkdir /etc/os-net-config
echo "network_config:" > /etc/os-net-config/config.yaml echo "network_config:" > /etc/os-net-config/config.yaml
@ -108,7 +112,7 @@ Requires=config-bmc-ips.service
After=config-bmc-ips.service After=config-bmc-ips.service
[Service] [Service]
ExecStart=/usr/local/bin/openstackbmc --os-user $os_user --os-password $os_password --os-tenant "$os_tenant" --os-auth-url $os_auth_url --os-project "$os_project" --os-user-domain "$os_user_domain" --os-project-domain "$os_project_domain" --instance $bm_instance --address $bmc_ip ExecStart=/usr/local/bin/openstackbmc --os-user $os_user --os-password $os_password --os-tenant "$os_tenant" --os-auth-url $os_auth_url --os-project "$os_project" --os-user-domain "$os_user_domain" --os-project-domain "$os_project_domain" --instance $bm_instance --address $bmc_ip $cache_status
Restart=always Restart=always
User=root User=root

View File

@ -35,7 +35,7 @@ import pyghmi.ipmi.bmc as bmc
class OpenStackBmc(bmc.Bmc): class OpenStackBmc(bmc.Bmc):
def __init__(self, authdata, port, address, instance, user, password, tenant, def __init__(self, authdata, port, address, instance, user, password, tenant,
auth_url, project, user_domain, project_domain): auth_url, project, user_domain, project_domain, cache_status):
super(OpenStackBmc, self).__init__(authdata, port=port, address=address) super(OpenStackBmc, self).__init__(authdata, port=port, address=address)
if not '/v3' in auth_url: if not '/v3' in auth_url:
# novaclient 7+ is backwards-incompatible :-( # novaclient 7+ is backwards-incompatible :-(
@ -53,6 +53,7 @@ class OpenStackBmc(bmc.Bmc):
user_domain_name=user_domain, user_domain_name=user_domain,
project_domain_name=project_domain) project_domain_name=project_domain)
self.instance = None self.instance = None
self.cache_status = cache_status
self.cached_status = None self.cached_status = None
self.target_status = None self.target_status = None
# At times the bmc service is started before important things like # At times the bmc service is started before important things like
@ -113,7 +114,9 @@ class OpenStackBmc(bmc.Bmc):
sys.exit(0) sys.exit(0)
def _instance_active(self): def _instance_active(self):
if self.cached_status is None or self.cached_status != self.target_status: if (self.cached_status is None or
self.cached_status != self.target_status or
not self.cache_status):
self.cached_status = self.novaclient.servers.get(self.instance).status self.cached_status = self.novaclient.servers.get(self.instance).status
return self.cached_status == 'ACTIVE' return self.cached_status == 'ACTIVE'
@ -220,6 +223,14 @@ def main():
required=False, required=False,
default='', default='',
help='The project domain for connecting to OpenStack') help='The project domain for connecting to OpenStack')
parser.add_argument('--cache-status',
dest='cache_status',
default=False,
action='store_true',
help='Cache the status of the managed instance. This '
'can reduce load on the host cloud, but if the '
'instance status is changed outside the BMC then '
'it may become out of sync.')
args = parser.parse_args() args = parser.parse_args()
# Default to ipv6 format, but if we get an ipv4 address passed in use the # Default to ipv6 format, but if we get an ipv4 address passed in use the
# appropriate format for pyghmi to listen on it. # appropriate format for pyghmi to listen on it.
@ -235,7 +246,8 @@ def main():
auth_url=args.auth_url, auth_url=args.auth_url,
project=args.project, project=args.project,
user_domain=args.user_domain, user_domain=args.user_domain,
project_domain=args.project_domain) project_domain=args.project_domain,
cache_status=args.cache_status)
mybmc.listen() mybmc.listen()

View File

@ -45,7 +45,8 @@ class TestOpenStackBmcInit(unittest.TestCase):
auth_url='http://keystone:5000', auth_url='http://keystone:5000',
project='', project='',
user_domain='', user_domain='',
project_domain='' project_domain='',
cache_status=False
) )
if old_nova: if old_nova:
mock_nova.assert_called_once_with(2, 'admin', 'password', 'admin', mock_nova.assert_called_once_with(2, 'admin', 'password', 'admin',
@ -91,7 +92,8 @@ class TestOpenStackBmcInit(unittest.TestCase):
auth_url='http://keystone:5000/v3', auth_url='http://keystone:5000/v3',
project='admin', project='admin',
user_domain='default', user_domain='default',
project_domain='default' project_domain='default',
cache_status=False
) )
mock_nova.assert_called_once_with(2, 'admin', 'password', mock_nova.assert_called_once_with(2, 'admin', 'password',
auth_url='http://keystone:5000/v3', auth_url='http://keystone:5000/v3',
@ -125,7 +127,8 @@ class TestOpenStackBmcInit(unittest.TestCase):
auth_url='http://keystone:5000', auth_url='http://keystone:5000',
project='', project='',
user_domain='', user_domain='',
project_domain='' project_domain='',
cache_status=False
) )
mock_nova.assert_called_once_with(2, 'admin', 'password', 'admin', mock_nova.assert_called_once_with(2, 'admin', 'password', 'admin',
'http://keystone:5000') 'http://keystone:5000')
@ -159,12 +162,14 @@ class TestOpenStackBmc(unittest.TestCase):
auth_url='http://keystone:5000', auth_url='http://keystone:5000',
project='', project='',
user_domain='', user_domain='',
project_domain='' project_domain='',
cache_status=False
) )
self.bmc.novaclient = self.mock_client self.bmc.novaclient = self.mock_client
self.bmc.instance = 'abc-123' self.bmc.instance = 'abc-123'
self.bmc.cached_status = None self.bmc.cached_status = None
self.bmc.target_status = None self.bmc.target_status = None
self.bmc.cache_status = False
def test_find_instance(self, mock_nova, mock_log, mock_init): def test_find_instance(self, mock_nova, mock_log, mock_init):
self._create_bmc(mock_nova) self._create_bmc(mock_nova)
@ -263,15 +268,26 @@ class TestOpenStackBmc(unittest.TestCase):
self.mock_client.servers.get.return_value = mock_server self.mock_client.servers.get.return_value = mock_server
self.bmc.target_status = 'ACTIVE' self.bmc.target_status = 'ACTIVE'
self.bmc.cached_status = 'SHUTOFF' self.bmc.cached_status = 'SHUTOFF'
self.bmc.cache_status = True
self.assertTrue(self.bmc._instance_active()) self.assertTrue(self.bmc._instance_active())
def test_instance_active_cached(self, mock_nova, mock_log, mock_init): def test_instance_active_cached(self, mock_nova, mock_log, mock_init):
self._create_bmc(mock_nova) self._create_bmc(mock_nova)
self.bmc.target_status = 'ACTIVE' self.bmc.target_status = 'ACTIVE'
self.bmc.cached_status = 'ACTIVE' self.bmc.cached_status = 'ACTIVE'
self.bmc.cache_status = True
self.assertTrue(self.bmc._instance_active()) self.assertTrue(self.bmc._instance_active())
self.assertFalse(self.mock_client.servers.get.called) self.assertFalse(self.mock_client.servers.get.called)
def test_cache_disabled(self, mock_nova, mock_log, mock_init):
self._create_bmc(mock_nova)
self.bmc.target_status = 'ACTIVE'
self.bmc.cached_status = 'ACTIVE'
mock_server = mock.Mock()
mock_server.status = 'SHUTOFF'
self.mock_client.servers.get.return_value = mock_server
self.assertFalse(self.bmc._instance_active())
@mock.patch('openstack_virtual_baremetal.openstackbmc.OpenStackBmc.' @mock.patch('openstack_virtual_baremetal.openstackbmc.OpenStackBmc.'
'_instance_active') '_instance_active')
def test_get_power_state(self, mock_active, mock_nova, mock_log, def test_get_power_state(self, mock_active, mock_nova, mock_log,
@ -364,7 +380,8 @@ class TestMain(unittest.TestCase):
auth_url='http://host:5000/v2.0', auth_url='http://host:5000/v2.0',
project='', project='',
user_domain='', user_domain='',
project_domain='' project_domain='',
cache_status=False
) )
mock_instance.listen.assert_called_once_with() mock_instance.listen.assert_called_once_with()
@ -388,6 +405,7 @@ class TestMain(unittest.TestCase):
auth_url='http://host:5000/v2.0', auth_url='http://host:5000/v2.0',
project='', project='',
user_domain='', user_domain='',
project_domain='' project_domain='',
cache_status=False
) )
mock_instance.listen.assert_called_once_with() mock_instance.listen.assert_called_once_with()

View File

@ -17,6 +17,14 @@ parameters:
The base image for the bmc instance. A CentOS 7 image is currently the The base image for the bmc instance. A CentOS 7 image is currently the
only one supported. only one supported.
bmc_use_cache:
type: boolean
default: false
description: |
Enable instance status caching on the BMC. This can reduce load on the
host cloud, but if an instance's status is changed outside the BMC it may
become out of sync.
baremetal_flavor: baremetal_flavor:
type: string type: string
default: baremetal default: baremetal
@ -172,6 +180,7 @@ resources:
$bm_node_count: {get_param: node_count} $bm_node_count: {get_param: node_count}
$bmc_prefix: {get_param: bmc_prefix} $bmc_prefix: {get_param: bmc_prefix}
$bmc_utility: {get_attr: [bmc_port, ip_address]} $bmc_utility: {get_attr: [bmc_port, ip_address]}
$bmc_use_cache: {get_param: bmc_use_cache}
$bm_prefix: {get_param: baremetal_prefix} $bm_prefix: {get_param: baremetal_prefix}
$private_net: {get_param: private_net} $private_net: {get_param: private_net}
$openstackbmc_script: {get_file: ../bin/openstackbmc} $openstackbmc_script: {get_file: ../bin/openstackbmc}