Improve Stack Status Check Loop

Improved loop that polls heat
for status of resource actions
taken

Change-Id: I1655b3143121fada985b44b798002ffc96ee9b42
This commit is contained in:
jh629g 2020-09-17 16:40:29 -05:00
parent e8b268c21b
commit cab06af183
19 changed files with 86 additions and 241 deletions

View File

@ -1,3 +1,4 @@
Andrii Ostapenko <andrii.ostapenko@att.com>
Chi Lo <cl566n@att.com> Chi Lo <cl566n@att.com>
Ian Wienand <iwienand@redhat.com> Ian Wienand <iwienand@redhat.com>
Michael Glaser <mg6596@att.com> Michael Glaser <mg6596@att.com>

View File

@ -1,7 +1,13 @@
CHANGES CHANGES
======= =======
* Improve Stack Status Check Loop
* Change Heat and Glance client to use internal endpoint
* Restrict dnspython to not use 2.0.0 version
* Use certificate when creating keystone session
* Ensure pip is installed on zuul executor
* Create editable Ranger-Agent Configuration * Create editable Ranger-Agent Configuration
* Fix glance client initialization Glance get image call is failing in engine
* create new tagging method in ranger-agent makefile * create new tagging method in ranger-agent makefile
* Dockerfile fix modular variable * Dockerfile fix modular variable
* Update Image build process * Update Image build process

1
bindep.txt Normal file
View File

@ -0,0 +1 @@
python3-dev [platform:dpkg test]

View File

@ -169,11 +169,11 @@ class NotifierController(object):
utils.STATUS_SUBMITTED: utils.STATUS_SUBMITTED:
error_code = ErrorCode.ORD_002.value error_code = ErrorCode.ORD_002.value
error_msg = ErrorCode.tostring(error_code) error_msg = ErrorCode.tostring(error_code)
elif kwargs.get('resource-template-name') == \ elif kwargs.get('resource-template-name') \
template_target.get('resource_template_name') and \ == template_target.get('resource_template_name') \
(template_target.get('status') == utils.STATUS_SUBMITTED or and (template_target.get('status') == utils.STATUS_SUBMITTED
template_target.get('resource_operation') == or template_target.get('resource_operation')
kwargs.get('resource-operation')): == kwargs.get('resource-operation')):
error_code = ErrorCode.ORD_001.value error_code = ErrorCode.ORD_001.value
error_msg = ErrorCode.tostring(error_code) error_msg = ErrorCode.tostring(error_code)

View File

@ -95,8 +95,8 @@ class ParsableErrorMiddleware(object):
user_locale = self.best_match_language(req.accept_language) user_locale = self.best_match_language(req.accept_language)
if (req.accept.best_match( if (req.accept.best_match(
['application/json', 'application/xml']) == ['application/json', 'application/xml'])
'application/xml'): == 'application/xml'):
try: try:
# simple check xml is valid # simple check xml is valid
fault = etree.fromstring('\n'.join(app_iter)) fault = etree.fromstring('\n'.join(app_iter))
@ -105,12 +105,12 @@ class ParsableErrorMiddleware(object):
for fault_string in fault.findall('faultstring'): for fault_string in fault.findall('faultstring'):
fault_string.text = i18n.translate(error, fault_string.text = i18n.translate(error,
user_locale) user_locale)
body = ['<error_message>' + etree.tostring(fault) + body = ['<error_message>' + etree.tostring(fault)
'</error_message>'] + '</error_message>']
except etree.XMLSyntaxError as err: except etree.XMLSyntaxError as err:
LOG.error(_('Error parsing HTTP response: %s') % err) LOG.error(_('Error parsing HTTP response: %s') % err)
body = ['<error_message>%s' % state['status_code'] + body = ['<error_message>%s' % state['status_code']
'</error_message>'] + '</error_message>']
state['headers'].append(('Content-Type', 'application/xml')) state['headers'].append(('Content-Type', 'application/xml'))
else: else:
try: try:

View File

@ -42,16 +42,17 @@ SERVICE_OPTS = [
"used by ranger agent to invoke keystone apis"), "used by ranger agent to invoke keystone apis"),
cfg.StrOpt("https_cacert", default=None, cfg.StrOpt("https_cacert", default=None,
help="Path to CA server certificate for SSL"), help="Path to CA server certificate for SSL"),
cfg.StrOpt('glance_api_url', default=None,
help="glance api internal url")
] ]
cfg.CONF.register_opts(SERVICE_OPTS, OPT_GROUP) cfg.CONF.register_opts(SERVICE_OPTS, OPT_GROUP)
cfg.CONF.register_opts([
cfg.StrOpt('glance_api_url', default=None, help="glance api internal url")
])
CONF = cfg.CONF CONF = cfg.CONF
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
logger = logging.logging.getLogger('keystoneauth')
logger.setLevel(logging.logging.INFO)
body_logger = logging.logging.getLogger('keystoneauth.session.body')
body_logger.setLevel(logging.logging.WARN)
def cached(func): def cached(func):
@ -79,9 +80,12 @@ def create_keystone_client(args):
project_domain_name=args['project_domain_name']) project_domain_name=args['project_domain_name'])
if args['https_cacert']: if args['https_cacert']:
session = ksc_session.Session(auth=auth, verify=args['https_cacert']) session = ksc_session.Session(
auth=auth,
verify=args['https_cacert'],
split_loggers=True)
else: else:
session = ksc_session.Session(auth=auth) session = ksc_session.Session(auth=auth, split_loggers=True)
return keystone_v3.Client(session=session, return keystone_v3.Client(session=session,
auth_url=args['auth_url'], auth_url=args['auth_url'],

View File

@ -14,6 +14,7 @@
# under the License. # under the License.
from heatclient import exc as heat_exc from heatclient import exc as heat_exc
import json
from ord.client.client import Clients from ord.client.client import Clients
from ord.common import exceptions as exc from ord.common import exceptions as exc
@ -25,8 +26,6 @@ class HeatClient(object):
_kc = None _kc = None
def __init__(self): def __init__(self):
# FIXME: we must not cache any clients because it done(must
# be done) by "Clients"
try: try:
if HeatClient._kc is None: if HeatClient._kc is None:
HeatClient._kc = Clients().keystone() HeatClient._kc = Clients().keystone()
@ -46,13 +45,11 @@ class HeatClient(object):
client, self._kc = Clients().heat(self._kc) client, self._kc = Clients().heat(self._kc)
try: try:
payload = client.stacks.get(stack_id) payload = client.stacks.get(stack_id)
# TODO: check behaviour in case it object not exist
except heat_exc.BaseException as e: except heat_exc.BaseException as e:
raise exc.HEATIntegrationError( raise exc.HEATIntegrationError(
action='stacks.get', details=e.message) action='stacks.get', details=e.message)
return payload return payload
# TODO: check real heatclient capabilities to lookup objects
def get_stack_by_name(self, name): def get_stack_by_name(self, name):
for stack in self.get_stacks(): for stack in self.get_stacks():
if stack.stack_name != name: if stack.stack_name != name:
@ -68,7 +65,9 @@ class HeatClient(object):
response = client.stacks.create( response = client.stacks.create(
stack_name=name, template=template) stack_name=name, template=template)
except heat_exc.BaseException as e: except heat_exc.BaseException as e:
raise exc.HEATStackCreateError(details=e.message) heat_err_msg = json.loads(e.message)['error']['message'] \
or e.message
raise exc.HEATStackCreateError(details=heat_err_msg)
return response return response
def update_stack(self, stack_id, template): def update_stack(self, stack_id, template):
@ -77,7 +76,9 @@ class HeatClient(object):
try: try:
response = client.stacks.update(stack_id, template=template) response = client.stacks.update(stack_id, template=template)
except heat_exc.BaseException as e: except heat_exc.BaseException as e:
raise exc.HEATStackUpdateError(details=e.message) heat_err_msg = json.loads(e.message)['error']['message'] \
or e.message
raise exc.HEATStackUpdateError(details=heat_err_msg)
return response return response
def delete_stack(self, stack_id): def delete_stack(self, stack_id):
@ -85,7 +86,9 @@ class HeatClient(object):
try: try:
client.stacks.delete(stack_id) client.stacks.delete(stack_id)
except heat_exc.BaseException as e: except heat_exc.BaseException as e:
raise exc.HEATStackDeleteError(details=e.message) heat_err_msg = json.loads(e.message)['error']['message'] \
or e.message
raise exc.HEATStackDeleteError(details=heat_err_msg)
def get_image_data_by_stackid(self, stack_id): def get_image_data_by_stackid(self, stack_id):
client, self._kc = Clients().heat(self._kc) client, self._kc = Clients().heat(self._kc)

View File

@ -225,47 +225,6 @@ class ClientInitializationException(ORDException):
message_template = 'Failed to initialize Heat' message_template = 'Failed to initialize Heat'
class RepoTimeoutException(ORDException):
error_code = ERROR_REPO_TIMEOUT
message_template = '[{label}] '\
'Timeout occurred while trying to connect to GIT repo'
class RepoIncorrectURL(ORDException):
error_code = ERROR_REPO_URL
message_template = '[{label}] An error occurred with the GIT repo url. ' \
'Check conf file to confirm URL'
class RepoNotExist(ORDException):
error_code = ERROR_REPO_NOT_EXIST
message_template = '[{label}] '\
'Git repo is incorrect or does not exist'
class FileNotInRepo(ORDException):
error_code = ERROR_FILE_NOT_IN_REPO
message_template = '[{label}] '\
'File does not exist in this Git repo'
class RepoNoPermission(ORDException):
error_code = ERROR_REPO_PERMISSION
message_template = '[{label}] '\
'Permission denied to repo. Check SSH keys'
class RepoUnknownException(ORDException):
error_code = ERROR_REPO_UNKNOWN
message_template = '[{label}] '\
'An unknown repo exception occurred - {unknown}'
class RepoInitializationException(ORDException):
error_code = ERROR_REPO_INIT
message_template = 'Failed to connect and download repo'
class RPCInitializationException(ORDException): class RPCInitializationException(ORDException):
error_code = ERROR_RPC_INIT error_code = ERROR_RPC_INIT
message_template = 'Failed to initialize RPC' message_template = 'Failed to initialize RPC'

View File

@ -31,7 +31,7 @@ from ord.openstack.common import log as logging
CONF = cfg.CONF CONF = cfg.CONF
CONF.register_opts([ CONF.register_opts([
cfg.IntOpt('heat_poll_interval', default=5, cfg.IntOpt('heat_poll_interval', default=10,
help='delay in seconds between two consecutive call to ' help='delay in seconds between two consecutive call to '
'heat.stacks.status'), 'heat.stacks.status'),
cfg.IntOpt('resource_status_check_wait', default=10, cfg.IntOpt('resource_status_check_wait', default=10,
@ -40,9 +40,9 @@ CONF.register_opts([
cfg.Opt('retry_limits', cfg.Opt('retry_limits',
default='3', default='3',
help='number of retry'), help='number of retry'),
cfg.IntOpt('resource_creation_timeout_min', default=1200, cfg.IntOpt('resource_creation_timeout_min', default=100,
help='max wait time for flavor and customer stacks'), help='max wait time for flavor and customer stacks'),
cfg.IntOpt('resource_creation_timeout_max', default=14400, cfg.IntOpt('resource_creation_timeout_max', default=300,
help='max wait time for image stacks'), help='max wait time for image stacks'),
cfg.BoolOpt('enable_rds_callback_check', cfg.BoolOpt('enable_rds_callback_check',
default=True, default=True,
@ -90,7 +90,7 @@ class WorkerFactory(object):
except Exception as exception: except Exception as exception:
WorkerThread._init_error = utils.ErrorCode.ORD_017.value WorkerThread._init_error = utils.ErrorCode.ORD_017.value
LOG.critical( LOG.critical(
"Unexpected error while initializing clients %s" % exception) "Unexpected error while initializing clients: %s" % exception)
finally: finally:
WorkerThread._threadPool = {} WorkerThread._threadPool = {}
if WorkerThread._init_error is None: if WorkerThread._init_error is None:
@ -98,13 +98,13 @@ class WorkerFactory(object):
@classmethod @classmethod
def removeWorker(cls, idnr): def removeWorker(cls, idnr):
LOG.info("Deleting thread : " + str(idnr)) LOG.info("Deleting thread: " + str(idnr))
try: try:
del WorkerThread._threadPool[idnr] del WorkerThread._threadPool[idnr]
except KeyError: except KeyError:
LOG.info("Thread was not found for deletion") LOG.info("Thread was not found for deletion")
raise exc.WorkerThreadError(thread_id=idnr) raise exc.WorkerThreadError(thread_id=idnr)
LOG.info("Thread was deleted : " + str(idnr)) LOG.info("Thread was deleted: " + str(idnr))
def __init__(self): def __init__(self):
LOG.info("initializing WorkerFactory._init_") LOG.info("initializing WorkerFactory._init_")
@ -117,8 +117,6 @@ class WorkerFactory(object):
template_type, heat_template): template_type, heat_template):
template_type = template_type.lower() template_type = template_type.lower()
# FIXME: this code has a none zero to fail in very unexpected
# way
randCrypt = SystemRandom() randCrypt = SystemRandom()
threadID = randCrypt.randint(1, 99999999) threadID = randCrypt.randint(1, 99999999)
if template_type == "hot": if template_type == "hot":
@ -130,7 +128,6 @@ class WorkerFactory(object):
elif template_type == "ansible": elif template_type == "ansible":
threadID = -1 threadID = -1
else: else:
# FIXME: too late for such check
raise exc.UnsupportedTemplateTypeError(template=template_type) raise exc.UnsupportedTemplateTypeError(template=template_type)
return threadID return threadID
@ -185,7 +182,7 @@ class WorkerThread(threading.Thread):
def run(self): def run(self):
LOG.debug("Thread Starting :: %s", self.threadID) LOG.debug("Thread Starting :: %s", self.threadID)
LOG.debug("operation %s for stack_name %s ", LOG.debug("operation %s for stack_name %s",
self.operation, self.stack_name) self.operation, self.stack_name)
try: try:
if self._is_engine_initialized(): if self._is_engine_initialized():
@ -351,7 +348,7 @@ class WorkerThread(threading.Thread):
return self._heat_client.get_stack(stack['id']) return self._heat_client.get_stack(stack['id'])
def _update_stack(self, template): def _update_stack(self, template):
LOG.debug("Update template for stack %s ", self.stack_name) LOG.debug("Updating template for stack %s ", self.stack_name)
stack = self._heat_client.get_stack_by_name(self.stack_name) stack = self._heat_client.get_stack_by_name(self.stack_name)
self._heat_client.update_stack(stack.id, template) self._heat_client.update_stack(stack.id, template)
@ -365,39 +362,36 @@ class WorkerThread(threading.Thread):
return stack return stack
def _wait_for_heat(self, stack, operation): def _wait_for_heat(self, stack, operation):
LOG.debug('Wait while HEAT do his job: stack=%s', self.stack_name) LOG.debug('Stack %s: waiting for Heat to complete', self.stack_name)
poll_interval = CONF.heat_poll_interval poll_interval = CONF.heat_poll_interval
LOG.debug("HEAT poll interval: %s", poll_interval)
max_wait_time = 0 max_wait_time = 0
if self.resource_type == 'image': if self.resource_type == 'image':
max_wait_time = CONF.resource_creation_timeout_max max_wait_time = CONF.resource_creation_timeout_max
else: else:
max_wait_time = CONF.resource_creation_timeout_min max_wait_time = CONF.resource_creation_timeout_min
LOG.debug("max_wait_time: %s", max_wait_time)
stack_status_transitions = StatusTransitions(stack.stack_status)
start_time = time.time() start_time = time.time()
waiting_time = 0 waiting_time = 0
status_check = HEATIntermediateStatusChecker(stack, operation) status_check = HEATIntermediateStatusChecker(stack, operation)
while status_check(stack) \ status = ''
while status != HEATIntermediateStatusChecker.STATUS_COMPLETE \
and status != HEATIntermediateStatusChecker.STATUS_FAIL \
and (waiting_time <= max_wait_time): and (waiting_time <= max_wait_time):
time.sleep(poll_interval) time.sleep(poll_interval)
waiting_time = time.time() - start_time waiting_time = time.time() - start_time
LOG.debug('%s waiting %s for %s', LOG.debug('Thread %s: Waiting for %s to finish;'
self.threadID, waiting_time, ' time elapsed: %s', self.threadID,
stack.stack_name) stack.stack_name, int(waiting_time))
LOG.debug('%s stack status transition: %s',
self.threadID, stack_status_transitions)
stack = self._heat_client.get_stack(stack.id) stack = self._heat_client.get_stack(stack.id)
stack_status_transitions.add(stack.stack_status) status = status_check(stack)
LOG.debug('%s done with waiting for stack %s: action=%s, status=%s', LOG.debug('Thread %s: Finished waiting'
self.threadID, stack.stack_name, status_check.action, ' for stack %s: action=%s, status=%s',
status_check.status) self.threadID, stack.stack_name,
status_check.action, status_check.status)
if status_check.is_fail: if status_check.is_fail:
if operation == utils.OPERATION_CREATE: if operation == utils.OPERATION_CREATE:
@ -416,27 +410,6 @@ class WorkerThread(threading.Thread):
raise exc.StackTimeoutError(operation=operation, stack=stack) raise exc.StackTimeoutError(operation=operation, stack=stack)
class StatusTransitions(object):
def __init__(self, status):
self.transitions = [status]
self.hits = [1]
def add(self, status):
if self.transitions[-1] != status:
self.transitions.append(status)
self.hits.append(0)
self.hits[-1] += 1
def __str__(self):
chunks = []
for status, hits in zip(self.transitions, self.hits):
if 1 < hits:
status = '{}({})'.format(status, hits)
chunks.append(status)
return ' ~> '.join(chunks)
class HEATIntermediateStatusChecker(object): class HEATIntermediateStatusChecker(object):
ACTION_CREATE = 'CREATE' ACTION_CREATE = 'CREATE'
ACTION_UPDATE = 'UPDATE' ACTION_UPDATE = 'UPDATE'

View File

@ -24,6 +24,8 @@ for admins to find messages related to a specific instance.
It also allows setting of formatting information through conf. It also allows setting of formatting information through conf.
""" """
from ord.openstack.common._i18n import _
from ord.openstack.common import local
import copy import copy
import inspect import inspect
@ -45,9 +47,6 @@ from six import moves
_PY26 = sys.version_info[0:2] == (2, 6) _PY26 = sys.version_info[0:2] == (2, 6)
from ord.openstack.common._i18n import _
from ord.openstack.common import local
_DEFAULT_LOG_DATE_FORMAT = "%Y-%m-%d %H:%M:%S" _DEFAULT_LOG_DATE_FORMAT = "%Y-%m-%d %H:%M:%S"
@ -317,8 +316,8 @@ class ContextAdapter(BaseLoggerAdapter):
extra.update(_dictify_context(context)) extra.update(_dictify_context(context))
instance = kwargs.pop('instance', None) instance = kwargs.pop('instance', None)
instance_uuid = (extra.get('instance_uuid') or instance_uuid = (extra.get('instance_uuid')
kwargs.pop('instance_uuid', None)) or kwargs.pop('instance_uuid', None))
instance_extra = '' instance_extra = ''
if instance: if instance:
instance_extra = CONF.instance_format % instance instance_extra = CONF.instance_format % instance
@ -653,8 +652,8 @@ class ContextFormatter(logging.Formatter):
else: else:
fmt = CONF.logging_default_format_string fmt = CONF.logging_default_format_string
if (record.levelno == logging.DEBUG and if (record.levelno == logging.DEBUG
CONF.logging_debug_format_suffix): and CONF.logging_debug_format_suffix):
fmt += " " + CONF.logging_debug_format_suffix fmt += " " + CONF.logging_debug_format_suffix
if sys.version_info < (3, 2): if sys.version_info < (3, 2):

View File

@ -144,8 +144,8 @@ def get_workers(name):
def prepare_service(argv=None): def prepare_service(argv=None):
i18n.enable_lazy() i18n.enable_lazy()
log_levels = (cfg.CONF.default_log_levels + log_levels = (cfg.CONF.default_log_levels
['stevedore=INFO']) + ['stevedore=INFO'])
cfg.set_defaults(log.log_opts, cfg.set_defaults(log.log_opts,
default_log_levels=log_levels) default_log_levels=log_levels)
if argv is None: if argv is None:

View File

@ -18,6 +18,7 @@ from ord.client import heat as ord_heat
from ord.common import exceptions as exc from ord.common import exceptions as exc
from ord.tests import base from ord.tests import base
import json
from unittest import mock from unittest import mock
@ -100,7 +101,8 @@ class TestHeatClient(base.BaseTestCase):
self.heat_client.stacks.delete.assert_called_with(stack_idnr) self.heat_client.stacks.delete.assert_called_with(stack_idnr)
def test_error_masquerading(self): def test_error_masquerading(self):
error = heat_exc.CommunicationError('ord-heat-stack-create-test') error = heat_exc.CommunicationError(
json.dumps({'error': {'message': 'ord-heat-stack-create-test'}}))
stack_idnr = '0' stack_idnr = '0'
stack_name = "test_stack" stack_name = "test_stack"

View File

@ -120,27 +120,6 @@ class TestWorkerThread(base.BaseTestCase):
stack.stack_name) stack.stack_name)
self.heat_client.delete_stack.assert_called_once_with(stack.id) self.heat_client.delete_stack.assert_called_once_with(stack.id)
def test_wait_for_heat(self):
time_time = self.patch('time.time', side_effect=itertools.count(1))
time_sleep = self.patch('time.sleep')
stack_wait = base.Dummy(
id='1', stack_name=self.stack_name,
stack_status='CREATE_IN_PROGRESS')
stack_ready = base.Dummy(
id='1', stack_name=self.stack_name, stack_status='CREATE_COMPLETE')
status_responses = [stack_wait] * 4 + [stack_ready]
self.heat_client.get_stack.side_effect = status_responses
# raise exception in case of failure
self.workerThread._wait_for_heat(stack_wait, utils.OPERATION_CREATE)
self.assertEqual(
[mock.call(CONF.heat_poll_interval)] * 5,
time_sleep.mock_calls)
self.assertEqual(6, time_time.call_count)
def test_wait_for_heat_fail(self): def test_wait_for_heat_fail(self):
self.patch('time.time', side_effect=itertools.count(1)) self.patch('time.time', side_effect=itertools.count(1))
self.patch('time.sleep') self.patch('time.sleep')
@ -148,47 +127,16 @@ class TestWorkerThread(base.BaseTestCase):
stack_wait = base.Dummy( stack_wait = base.Dummy(
id='1', stack_name=self.stack_name, id='1', stack_name=self.stack_name,
stack_status='CREATE_IN_PROGRESS') stack_status='CREATE_IN_PROGRESS')
stack_ready = base.Dummy( stack_failed = base.Dummy(
id='1', stack_name=self.stack_name, stack_status='CREATE_FAILED', id='1', stack_name=self.stack_name, stack_status='CREATE_FAILED',
stack_status_reason='Stack fail due to resource creation') stack_status_reason='Stack fail due to resource creation')
status_responses = [stack_wait] * 4 + [stack_ready] self.heat_client.get_stack.return_value = stack_failed
self.heat_client.get_stack.side_effect = status_responses
self.assertRaises( self.assertRaises(
exc.HEATStackCreateError, self.workerThread._wait_for_heat, exc.HEATStackCreateError, self.workerThread._wait_for_heat,
stack_wait, utils.OPERATION_CREATE) stack_wait, utils.OPERATION_CREATE)
def test_wait_for_heat_race(self):
self.patch('time.time', side_effect=itertools.count(1))
self.patch('time.sleep')
stack_initial = base.Dummy(
id='1', stack_name=self.stack_name, stack_status='UPDATE_COMPLETE',
updated_time='2016-06-02T16:30:48Z')
stack_wait = base.Dummy(
id='1', stack_name=self.stack_name,
stack_status='UPDATE_IN_PROGRESS',
updated_time='2016-06-02T16:30:48Z')
stack_ready = base.Dummy(
id='1', stack_name=self.stack_name, stack_status='UPDATE_COMPLETE',
updated_time='2016-06-02T16:30:50Z')
status_responses = [stack_initial]
status_responses += [stack_wait] * 2
status_responses += [stack_ready]
status_transition = workerfactory.StatusTransitions('_unittest_')
self.patch(
'ord.engine.workerfactory.StatusTransitions',
return_value=status_transition)
self.heat_client.get_stack.side_effect = status_responses
self.workerThread._wait_for_heat(stack_initial, utils.OPERATION_MODIFY)
self.assertEqual('UPDATE_COMPLETE', status_transition.transitions[-1])
def test_run(self): def test_run(self):
self.workerThread._execute_operation = execute = mock.Mock() self.workerThread._execute_operation = execute = mock.Mock()
execute.return_value = 'OPERATION_STATUS' execute.return_value = 'OPERATION_STATUS'
@ -268,19 +216,6 @@ class TestWorkerThread(base.BaseTestCase):
db_api.update_target_data.reset_mock() db_api.update_target_data.reset_mock()
class TestStatusTransitions(base.BaseTestCase):
def test(self):
for data, expect in [
('A', 'A'),
('AA', 'A(2)'),
('ABC', 'A ~> B ~> C'),
('AABBCC', 'A(2) ~> B(2) ~> C(2)')]:
subject = workerfactory.StatusTransitions(data[0])
for entity in data[1:]:
subject.add(entity)
self.assertEqual(expect, str(subject))
class TestHEATIntermediateStatusChecker(base.BaseTestCase): class TestHEATIntermediateStatusChecker(base.BaseTestCase):
def test_scenario(self): def test_scenario(self):
cls = workerfactory.HEATIntermediateStatusChecker cls = workerfactory.HEATIntermediateStatusChecker

View File

@ -3,7 +3,8 @@
# process, which may cause wedges in the gate later. # process, which may cause wedges in the gate later.
amqp>=2.5.2 amqp>=2.5.2
hacking>=0.12.0,!=0.13.0,<0.14 # Apache-2.0 hacking>=3.0.1,<3.1.0 # Apache-2.0
pep257==0.7.0 # MIT License
bandit>=1.5.1 bandit>=1.5.1
coverage>=4.0 coverage>=4.0
python-subunit>=0.0.18 python-subunit>=0.0.18

View File

@ -130,9 +130,9 @@ class _Win32Colorizer(object):
import pywintypes import pywintypes
try: try:
screenBuffer.SetConsoleTextAttribute( screenBuffer.SetConsoleTextAttribute(
win32console.FOREGROUND_RED | win32console.FOREGROUND_RED
win32console.FOREGROUND_GREEN | | win32console.FOREGROUND_GREEN
win32console.FOREGROUND_BLUE) | win32console.FOREGROUND_BLUE)
except pywintypes.error: except pywintypes.error:
return False return False
else: else:

View File

@ -67,5 +67,6 @@ def main(argv):
install.install_dependencies() install.install_dependencies()
print_help(venv, root) print_help(venv, root)
if __name__ == '__main__': if __name__ == '__main__':
main(sys.argv) main(sys.argv)

View File

@ -70,8 +70,8 @@ class InstallVenv(object):
check_exit_code)[0] check_exit_code)[0]
def get_distro(self): def get_distro(self):
if (os.path.exists('/etc/fedora-release') or if (os.path.exists('/etc/fedora-release')
os.path.exists('/etc/redhat-release')): or os.path.exists('/etc/redhat-release')):
return Fedora( return Fedora(
self.root, self.venv, self.requirements, self.root, self.venv, self.requirements,
self.test_requirements, self.py_version, self.project) self.test_requirements, self.py_version, self.project)

View File

@ -1,50 +1,10 @@
- hosts: all - hosts: all
roles: roles:
- ensure-pip - ensure-pip
- ensure-docker
tasks: tasks:
- include_vars: vars.yaml - include_vars: vars.yaml
- name: Install Docker (Debian)
when: ansible_os_family == 'Debian'
block:
- file:
path: "{{ item }}"
state: directory
with_items:
- /etc/docker/
- /etc/systemd/system/docker.service.d/
- /var/lib/docker/
- mount:
path: /var/lib/docker/
src: tmpfs
fstype: tmpfs
opts: size=25g
state: mounted
- copy: "{{ item }}"
with_items:
- content: "{{ docker_daemon | to_json }}"
dest: /etc/docker/daemon.json
- src: files/docker-systemd.conf
dest: /etc/systemd/system/docker.service.d/
- apt_key:
url: https://download.docker.com/linux/ubuntu/gpg
- apt_repository:
repo: deb http://{{ zuul_site_mirror_fqdn }}/deb-docker bionic stable
- apt:
name: "{{ item }}"
allow_unauthenticated: True
with_items:
- docker-ce
- pip:
name: docker
version: 2.7.0
- iptables:
action: insert
chain: INPUT
in_interface: docker0
jump: ACCEPT
become: True
- name: Make images - name: Make images
when: not publish when: not publish
block: block:

View File

@ -5,14 +5,15 @@ envlist = py36,pep8
skipsdist = True skipsdist = True
[testenv] [testenv]
basepython = python3.6 basepython = python3
usedevelop = True usedevelop = True
setenv = setenv =
VIRTUAL_ENV={envdir} VIRTUAL_ENV={envdir}
PYTHONWARNINGS=default::DeprecationWarning PYTHONWARNINGS=default::DeprecationWarning
install_command = pip install {opts} {packages}
commands = stestr run
deps = -r {toxinidir}/requirements.txt deps = -r {toxinidir}/requirements.txt
-r {toxinidir}/test-requirements.txt -r {toxinidir}/test-requirements.txt
commands = stestr run
[testenv:bandit] [testenv:bandit]
deps = .[bandit] deps = .[bandit]
@ -21,7 +22,6 @@ commands = bandit -r ord -n5 -c bandit.yaml
[testenv:pep8] [testenv:pep8]
commands = commands =
flake8 {posargs} flake8 {posargs}
{[testenv:bandit]commands}
[testenv:venv] [testenv:venv]
commands = {posargs} commands = {posargs}
@ -41,6 +41,6 @@ commands = oslo_debug_helper {posargs}
[flake8] [flake8]
show-source = True show-source = True
ignore = F841,H101,H405 ignore = F841,H101,H405,W503,E902
builtins = _ builtins = _
exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build