Merge "Use new Ironic's heartbeat API"

This commit is contained in:
Jenkins 2017-04-25 11:52:05 +00:00 committed by Gerrit Code Review
commit 18b834e52c
2 changed files with 41 additions and 55 deletions

View File

@ -27,6 +27,7 @@ from oslo_service import loopingcall
from oslo_utils import excutils
from oslo_utils import fileutils
import six
import six.moves.urllib.parse as urlparse
from ironic.common import boot_devices
from ironic.common import dhcp_factory
@ -473,49 +474,23 @@ class FuelAgentDeploy(base.DeployInterface):
def take_over(self, task):
pass
class FuelAgentVendor(base.VendorInterface):
def get_properties(self):
"""Return the properties of the interface.
:returns: dictionary of <property name>:<property description> entries.
"""
return COMMON_PROPERTIES
def validate(self, task, method, **kwargs):
"""Validate the driver-specific Node deployment info.
:param task: a TaskManager instance
:param method: method to be validated
"""
_parse_driver_info(task.node)
if not kwargs.get('status'):
raise exception.MissingParameterValue(_('Unknown Fuel Agent status'
' on a node.'))
if not kwargs.get('address'):
raise exception.MissingParameterValue(_('Fuel Agent must pass '
'address of a node.'))
@base.passthru(['POST'])
@task_manager.require_exclusive_lock
def heartbeat(self, task, **kwargs):
def heartbeat(self, task, callback_url):
"""Continues the deployment of baremetal node."""
node = task.node
task.process_event('resume')
err_msg = _('Failed to continue deployment with Fuel Agent.')
agent_status = kwargs.get('status')
if agent_status != 'ready':
LOG.error(_LE('Deploy failed for node %(node)s. Fuel Agent is not '
'in ready state, error: %(error)s'), {'node': node.uuid,
'error': kwargs.get('error_message')})
deploy_utils.set_failed_state(task, err_msg)
# NOTE(pas-ha) this driver does not support cleaning,
# so the only valid state to continue on heartbeat is DEPLOYWAIT
if node.provision_state != states.DEPLOYWAIT:
LOG.warning(_LW('Call back from %(node)s in invalid provision '
'state %(state)s'),
{'node': node.uuid, 'state': node.provision_state})
return
task.upgrade_lock(purpose='deploy')
task.process_event('resume')
params = _parse_driver_info(node)
params['host'] = kwargs.get('address')
params['host'] = urlparse.urlparse(callback_url).netloc.split(':')[0]
cmd = ('%s --data_driver ironic --config-file '
'/etc/fuel-agent/fuel-agent.conf' % params.pop('script'))
if CONF.debug:
@ -554,7 +529,7 @@ class FuelAgentVendor(base.VendorInterface):
msg = (_('Deploy failed for node %(node)s. Error: %(error)s') %
{'node': node.uuid, 'error': e})
LOG.error(msg)
deploy_utils.set_failed_state(task, msg)
deploy_utils.set_failed_state(task, msg, collect_logs=False)
else:
task.process_event('done')
LOG.info(_LI('Deployment to node %s done'), task.node.uuid)

View File

@ -20,6 +20,10 @@ import requests
from fuel_agent.utils import utils
_GET_ADDR_MAX_ITERATION = 50
_POST_CALLBACK_MAX_ITERATION = 50
_RETRY_INTERVAL = 5
def _process_error(message):
sys.stderr.write(message)
@ -56,28 +60,35 @@ def main():
# The leading `01-' denotes the device type (Ethernet) and is not a part of
# the MAC address
boot_mac = bootif[3:].replace('-', ':')
for n in range(10):
for n in range(_GET_ADDR_MAX_ITERATION):
boot_ip = utils.get_interface_ip(boot_mac)
if boot_ip is not None:
break
time.sleep(10)
time.sleep(_RETRY_INTERVAL)
else:
_process_error('Cannot find IP address of boot interface.')
data = {"address": boot_ip,
"status": "ready",
"error_message": "no errors"}
# NOTE(pas-ha) supporting only Ironic API >= 1.22 !!!
headers = {'Content-Type': 'application/json',
'Accept': 'application/json',
'X-OpenStack-Ironic-API-Version': '1.22'}
data = {"callback_url": "ssh://" + boot_ip}
heartbeat = '{api_url}/v1/heartbeat/{uuid}'.format(api_url=api_url,
uuid=deployment_id)
passthru = '%(api-url)s/v1/nodes/%(deployment_id)s/vendor_passthru' \
'/heartbeat' % {'api-url': api_url,
'deployment_id': deployment_id}
try:
resp = requests.post(passthru, data=json.dumps(data),
headers={'Content-Type': 'application/json',
'Accept': 'application/json'})
except Exception as e:
_process_error(str(e))
if resp.status_code != 202:
_process_error('Wrong status code %d returned from Ironic API' %
resp.status_code)
for attempt in range(_POST_CALLBACK_MAX_ITERATION):
try:
resp = requests.post(heartbeat, data=json.dumps(data),
headers=headers)
except Exception as e:
error = str(e)
else:
if resp.status_code != 202:
error = ('Wrong status code %d returned from Ironic API' %
resp.status_code)
else:
break
time.sleep(_RETRY_INTERVAL)
else:
# executed only when whole for block was executed w/o breaks
_process_error(error)