Merge branch 'master' into f/centos8

Change-Id: I3acd923c1de5af80ce83d2c60272bf50cca733fa
This commit is contained in:
Shuicheng Lin 2020-04-01 21:27:55 +08:00
commit 4dc4325ab0
20 changed files with 854 additions and 22 deletions

View File

@ -10,15 +10,21 @@
jobs: jobs:
- openstack-tox-linters - openstack-tox-linters
- openstack-tox-pep8 - openstack-tox-pep8
- fault-tox-pylint
- stx-fault-build - stx-fault-build
- fault-rest-api-py27 - fault-rest-api-py27
- fault-rest-api-py35 - fault-rest-api-py36
gate: gate:
jobs: jobs:
- openstack-tox-linters - openstack-tox-linters
- openstack-tox-pep8 - openstack-tox-pep8
- fault-tox-pylint
- fault-rest-api-py27 - fault-rest-api-py27
- fault-rest-api-py35 - fault-rest-api-py36
post:
jobs:
- stx-fault-upload-git-mirror
# Perform just a build # Perform just a build
- job: - job:
@ -58,7 +64,7 @@
parent: tox parent: tox
description: | description: |
Run py27 test for fm-rest-api Run py27 test for fm-rest-api
nodeset: ubuntu-xenial nodeset: ubuntu-bionic
required-projects: required-projects:
- starlingx/config - starlingx/config
vars: vars:
@ -66,13 +72,115 @@
tox_extra_args: -c fm-rest-api/fm/tox.ini tox_extra_args: -c fm-rest-api/fm/tox.ini
- job: - job:
name: fault-rest-api-py35 name: fault-rest-api-py36
parent: tox parent: tox
description: | description: |
Run py35 test for fm-rest-api Run py36 test for fm-rest-api
nodeset: ubuntu-xenial nodeset: ubuntu-bionic
required-projects: required-projects:
- starlingx/config - starlingx/config
vars: vars:
tox_envlist: py35 tox_envlist: py36
tox_extra_args: -c fm-rest-api/fm/tox.ini tox_extra_args: -c fm-rest-api/fm/tox.ini
- job:
name: fault-tox-pylint
parent: tox
description: |
Run pylint for python files in fault
required-projects:
- starlingx/config
vars:
tox_envlist: pylint
- job:
name: stx-fault-upload-git-mirror
parent: upload-git-mirror
description: >
Mirrors opendev.org/starlingx/fault to
github.com/starlingx/fault
vars:
git_mirror_repository: starlingx/fault
secrets:
- name: git_mirror_credentials
secret: stx-fault-github-secret
pass-to-parent: true
- secret:
name: stx-fault-github-secret
data:
user: git
host: github.com
# yamllint disable-line rule:line-length
host_key: github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==
ssh_key: !encrypted/pkcs1-oaep
- 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
- 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
- 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
- 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
- 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
- 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
- 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

View File

@ -13,7 +13,7 @@
import copy import copy
from . import constants from . import constants
import six import six
import fm_core import fm_core # pylint: disable=import-error
import threading import threading
fm_api_lock = threading.Lock() fm_api_lock = threading.Lock()

View File

@ -0,0 +1,8 @@
[run]
branch = True
source = fm
omit = fm/tests/*
[report]
ignore_errors = True

View File

@ -0,0 +1,14 @@
# Copyright 2020 Intel Corporation.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

View File

@ -0,0 +1,79 @@
# Copyright 2020 Intel Corporation.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""Base classes for API tests."""
from oslo_config import cfg
import pecan
import pecan.testing
from fm.tests import base
from fm.common import context as fm_context
PATH_PREFIX = '/v1'
class FunctionalTest(base.TestCase):
"""Used for functional tests of Pecan controllers where you need to
test your literal application and its integration with the
framework.
"""
SOURCE_DATA = {'test_source': {'somekey': '666'}}
def setUp(self):
super(FunctionalTest, self).setUp()
self.context = fm_context.RequestContext(is_admin=True)
self.app = self._make_app()
def _make_app(self):
cfg.CONF.set_override("debug", True)
self.config = {
'app': {
'root': 'fm.api.controllers.root.RootController',
'modules': ['fm.api'],
'acl_public_routes': ['/', '/v1'],
},
}
return pecan.testing.load_test_app(self.config)
def tearDown(self):
super(FunctionalTest, self).tearDown()
pecan.set_config({}, overwrite=True)
def get_json(self, path, expect_errors=False, headers=None,
extra_environ=None, q=[], path_prefix=PATH_PREFIX, **params):
full_path = path_prefix + path
query_params = {'q.field': [],
'q.value': [],
'q.op': [],
}
for query in q:
for name in ['field', 'op', 'value']:
query_params['q.%s' % name].append(query.get(name, ''))
all_params = {}
all_params.update(params)
if q:
all_params.update(query_params)
response = self.app.get(full_path,
params=all_params,
headers=headers,
extra_environ=extra_environ,
expect_errors=expect_errors)
if not expect_errors:
response = response.json
return response

View File

@ -0,0 +1,30 @@
# Copyright 2020 Intel Corporation.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from fm.tests.api import base
class TestBase(base.FunctionalTest):
def test_api_setup(self):
pass
def test_bad_uri(self):
response = self.get_json('/bad/path',
expect_errors=True,
headers={"Accept": "application/json"})
self.assertEqual(response.status_int, 404)
self.assertEqual(response.content_type, "application/json")
self.assertTrue(response.json['error_message'])

View File

@ -0,0 +1,40 @@
# Copyright 2013 Red Hat, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
# Copyright 2020 Intel Corporation.
#
from fm.tests.api import base
class TestRoot(base.FunctionalTest):
def test_get_root(self):
data = self.get_json('/', path_prefix='')
self.assertEqual(data['default_version']['id'], 'v1')
# Check fields are not empty
[self.assertNotIn(f, ['', []]) for f in data.keys()]
class TestV1Root(base.FunctionalTest):
def test_get_v1_root(self):
data = self.get_json('/')
self.assertEqual(data['id'], 'v1')
# Check fields are not empty
[self.assertNotIn(f, ['', []]) for f in data.keys()]
# Check if the resources are present
self.assertIn({'type': 'application/vnd.openstack.fm.v1+json',
'base': 'application/json'}, data['media_types'])

View File

@ -19,13 +19,24 @@ Allows overriding of config for use of fakes, and some black magic for
inline callbacks. inline callbacks.
""" """
import sys
import os
import fixtures import fixtures
import mock
import testtools import testtools
from oslo_config import cfg from oslo_config import cfg
from oslo_db.sqlalchemy import enginefacade
from oslo_log import log as logging from oslo_log import log as logging
from fm.db import migration
from fm.tests import conf_fixture
CONF = cfg.CONF CONF = cfg.CONF
_DB_CACHE = None
sys.modules['fm_core'] = mock.Mock()
class TestCase(testtools.TestCase): class TestCase(testtools.TestCase):
@ -35,12 +46,44 @@ class TestCase(testtools.TestCase):
"""Run before each test method to initialize test environment.""" """Run before each test method to initialize test environment."""
super(TestCase, self).setUp() super(TestCase, self).setUp()
test_timeout = os.environ.get('OS_TEST_TIMEOUT', 0)
try:
test_timeout = int(test_timeout)
except ValueError:
# If timeout value is invalid do not set a timeout.
test_timeout = 0
if test_timeout > 0:
self.useFixture(fixtures.Timeout(test_timeout, gentle=True))
self.useFixture(fixtures.NestedTempfile())
self.useFixture(fixtures.TempHomeDir())
if (os.environ.get('OS_STDOUT_CAPTURE') == 'True' or
os.environ.get('OS_STDOUT_CAPTURE') == '1'):
stdout = self.useFixture(fixtures.StringStream('stdout')).stream
self.useFixture(fixtures.MonkeyPatch('sys.stdout', stdout))
if (os.environ.get('OS_STDERR_CAPTURE') == 'True' or
os.environ.get('OS_STDERR_CAPTURE') == '1'):
stderr = self.useFixture(fixtures.StringStream('stderr')).stream
self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr))
self.log_fixture = self.useFixture(fixtures.FakeLogger())
def fake_logging_setup(*args): def fake_logging_setup(*args):
pass pass
self.useFixture( self.useFixture(
fixtures.MonkeyPatch('oslo_log.log.setup', fake_logging_setup)) fixtures.MonkeyPatch('oslo_log.log.setup', fake_logging_setup))
logging.register_options(CONF) logging.register_options(CONF)
self.useFixture(conf_fixture.ConfFixture(CONF))
global _DB_CACHE
if not _DB_CACHE:
engine = enginefacade.get_legacy_facade().get_engine()
engine.dispose()
engine.connect()
migration.db_sync(engine=engine)
def tearDown(self): def tearDown(self):
super(TestCase, self).tearDown() super(TestCase, self).tearDown()

View File

@ -0,0 +1,35 @@
# Copyright 2010 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
# Copyright 2020 Intel Corporation.
from oslo_config import cfg
from oslo_config import fixture as config_fixture
CONF = cfg.CONF
class ConfFixture(config_fixture.Config):
"""Fixture to manage global conf settings."""
def __init__(self, conf):
self.conf = conf
def setUp(self):
super(ConfFixture, self).setUp()
self.conf.set_default('connection', "sqlite://", group='database')
self.addCleanup(self.conf.reset)

View File

@ -0,0 +1,14 @@
# Copyright 2020 Intel Corporation.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

View File

@ -0,0 +1,32 @@
# Copyright 2020 Intel Corporation.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""Fault DB test base class."""
import abc
import six
from fm.common import context
from fm.tests import base
INIT_VERSION = 0
@six.add_metaclass(abc.ABCMeta)
class DbTestCase(base.TestCase):
def setUp(self):
super(DbTestCase, self).setUp()
self.admin_context = context.make_context(is_admin=True)

View File

@ -0,0 +1,24 @@
# Copyright 2020 Intel Corporation.
#
# SPDX-License-Identifier: Apache-2.0
#
"""Tests for Alarm via the DB API"""
from fm.db import api as dbapi
from fm.tests.db import base
from fm.tests.db import utils
class DbAlarmTestCase(base.DbTestCase):
def setUp(self):
super(DbAlarmTestCase, self).setUp()
self.dbapi = dbapi.get_instance()
def test_create_alarm(self):
uuid = 1234567
alarm = utils.get_test_alarm(uuid=uuid)
alarm_exist = self.dbapi.alarm_create(alarm)
self.assertEqual(uuid, alarm_exist.uuid)

View File

@ -0,0 +1,52 @@
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
# Copyright 2020 Intel Corporation
"""Fault test utilities."""
from fm.db import api as db_api
from fm_api import constants
def get_test_alarm(**kw):
alarm = {
'uuid': kw.get('uuid'),
'alarm_id': kw.get('alarm_id', constants.FM_ALARM_ID_VM_FAILED),
'alarm_state': kw.get('alarm_state', constants.FM_ALARM_STATE_SET),
'entity_type_id': kw.get('entity_type_id', constants.FM_ENTITY_TYPE_INSTANCE),
'entity_instance_id': kw.get('entity_instance_id',
constants.FM_ENTITY_TYPE_INSTANCE + '=' +
'a4e4cdb7-2ee6-4818-84c8-5310fcd67b5d'),
'severity': kw.get('severity', constants.FM_ALARM_SEVERITY_CRITICAL),
'reason_text': kw.get('reason_text', "Unknown"),
'alarm_type': kw.get('alarm_type', constants.FM_ALARM_TYPE_5),
'probable_cause': kw.get('probable_cause', constants.ALARM_PROBABLE_CAUSE_8),
'proposed_repair_action': None,
'service_affecting': False,
'suppression': False
}
return alarm
def create_test_alarm(**kw):
"""Create test alarm entry in DB and return alarm DB object.
Function to be used to create test alarm objects in the database.
:param kw: kwargs with overriding values for alarm's attributes.
:returns: Test alarm DB object.
"""
alarm = get_test_alarm(**kw)
# Let DB generate ID if it isn't specified explicitly
dbapi = db_api.get_instance()
return dbapi.alarm_create(alarm)

View File

@ -0,0 +1,29 @@
# Copyright 2020 Intel Corporation.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from fm.db import migration
from fm.db.sqlalchemy import api as db_api
from fm.tests.db import base
class DbSyncTestCase(base.DbTestCase):
def setUp(self):
super(DbSyncTestCase, self).setUp()
def test_sync_and_version(self):
migration.db_sync()
engine = db_api.get_engine()
v = migration.get_backend().db_version(engine, migration.MIGRATE_REPO_PATH, None)
self.assertTrue(v > base.INIT_VERSION)

View File

@ -2,12 +2,24 @@ hacking!=0.13.0,<0.14,>=0.12.0
bashate >= 0.2 bashate >= 0.2
PyYAML >= 3.1.0 PyYAML >= 3.1.0
yamllint >= 0.5.2 yamllint >= 0.5.2
stestr stestr != 3.0.0
testtools!=1.2.0,>=0.9.36 testtools!=1.2.0,>=0.9.36
iso8601 iso8601
stestr
mock mock
cython cython
oslo.log oslo.log
oslo.concurrency oslo.i18n # Apache-2.0
oslo.config>=3.7.0 # Apache-2.0
oslo.concurrency>=3.7.1 # Apache-2.0
oslo.db>=4.1.0 # Apache-2.0
oslo.service>=1.10.0 # Apache-2.0
oslo.utils>=3.5.0 # Apache-2.0
oslo.serialization>=1.10.0,!=2.19.1 # Apache-2.0
oslo_policy
oslo_versionedobjects
python-keystoneclient>=3.8.0 # Apache-2.0
keystonemiddleware>=4.12.0 # Apache-2.0
pecan>=1.0.0
WSME>=0.5b2
httplib2
keyring <= 18.0.1

View File

@ -1,5 +1,5 @@
[tox] [tox]
envlist = py27,py35 envlist = py27,py36
minversion = 2.3 minversion = 2.3
skipsdist = True skipsdist = True
stxdir = {toxinidir}/../../../ stxdir = {toxinidir}/../../../
@ -12,6 +12,9 @@ setenv = VIRTUAL_ENV={envdir}
OS_TEST_TIMEOUT=60 OS_TEST_TIMEOUT=60
deps = -r{toxinidir}/test-requirements.txt deps = -r{toxinidir}/test-requirements.txt
-e{[tox]stxdir}/config/tsconfig/tsconfig -e{[tox]stxdir}/config/tsconfig/tsconfig
-e{[tox]stxdir}/config/sysinv/cgts-client/cgts-client
-e{[tox]stxdir}/fault/fm-api
-e{[tox]stxdir}/fault/fm-rest-api/fm
[testenv:venv] [testenv:venv]
basepython = python3 basepython = python3
@ -23,12 +26,22 @@ commands =
stestr run {posargs} stestr run {posargs}
stestr slowest stestr slowest
[testenv:py35] [testenv:py36]
basepython = python3.5 basepython = python3.6
commands = commands =
stestr run {posargs} stestr run {posargs}
stestr slowest stestr slowest
[testenv:cover]
deps = {[testenv]deps}
coverage
setenv = {[testenv]setenv}
PYTHON=coverage run --parallel-mode
commands =
coverage erase
stestr run {posargs}
coverage combine
coverage html -d cover
coverage xml -o cover/coverage.xml
coverage report

267
pylint.rc Executable file
View File

@ -0,0 +1,267 @@
[MASTER]
# Specify a configuration file.
rcfile=pylint.rc
# Python code to execute, usually for sys.path manipulation such as
# pygtk.require().
#init-hook=
# Add files or directories to the blacklist. Should be base names, not paths.
ignore=
# Pickle collected data for later comparisons.
persistent=yes
# List of plugins (as comma separated values of python modules names) to load,
# usually to register additional checkers.
load-plugins=
# Use multiple processes to speed up Pylint.
jobs=4
# Allow loading of arbitrary C extensions. Extensions are imported into the
# active Python interpreter and may run arbitrary code.
unsafe-load-any-extension=no
# A comma-separated list of package or module names from where C extensions may
# be loaded. Extensions are loading into the active Python interpreter and may
# run arbitrary code
extension-pkg-whitelist=lxml.etree,greenlet
[MESSAGES CONTROL]
# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option
# multiple time.
#enable=
# Disable the message, report, category or checker with the given id(s). You
# can either give multiple identifier separated by comma (,) or put this option
# multiple time (only on the command line, not in the configuration file where
# it should appear only once).
# See "Messages Control" section of
# https://pylint.readthedocs.io/en/latest/user_guide
# We are disabling (C)onvention
# We are disabling (R)efactor
# We are selectively disabling (W)arning
# W0102 dangerous-default-value
# W0106 expression-not-assigned
# W0107 unnecessary-pass
# W0110 deprecated-lambda
# W0201 attribute-defined-outside-init
# W0212 protected-access
# W0221 arguments-differ
# W0223 abstract-method
# W0231 super-init-not-called
# W0235 useless-super-delegation
# W0311 bad-indentation
# W0403 relative-import (this needs to be fixed in py3)
# W0603 global-statement
# W0612 unused-variable
# W0613 unused-argument
# W0621 redefined-outer-name
# W0622 redefined-builtin
# W0703 broad-except
# W1401 anomalous-backslash-in-string
# E are error codes
# E0604 invalid-all-object
# E1101 no-member
# E1102 not-callable
# E1120 no-value-for-parameter
# E1121 too-many-function-args
disable=C, R, fixme,
W0102,W0106,W0107,W0110,W0201,W0212,W0221,W0223,W0231,W0235,
W0311,W0403,W0603,W0612,W0613,W0621,W0622,W0703,W1401,
E0604,E1101,E1102,E1120,E1121
[REPORTS]
# Set the output format. Available formats are text, parseable, colorized, msvs
# (visual studio) and html
output-format=text
# Put messages in a separate file for each module / package specified on the
# command line instead of printing them on stdout. Reports (if any) will be
# written in a file name "pylint_global.[txt|html]".
files-output=no
# Tells whether to display a full report or only the messages
reports=yes
# Python expression which should return a note less than 10 (10 is the highest
# note). You have access to the variables errors warning, statement which
# respectively contain the number of errors / warnings messages and the total
# number of statements analyzed. This is used by the global evaluation report
# (RP0004).
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
[SIMILARITIES]
# Minimum lines number of a similarity.
min-similarity-lines=4
# Ignore comments when computing similarities.
ignore-comments=yes
# Ignore docstrings when computing similarities.
ignore-docstrings=yes
[FORMAT]
# Maximum number of characters on a single line.
max-line-length=85
# Maximum number of lines in a module
max-module-lines=1000
# String used as indentation unit. This is usually 4 spaces or "\t" (1 tab).
indent-string=' '
[TYPECHECK]
# Tells whether missing members accessed in mixin class should be ignored. A
# mixin class is detected if its name ends with "mixin" (case insensitive).
ignore-mixin-members=yes
# List of module names for which member attributes should not be checked
# (useful for modules/projects where namespaces are manipulated during runtime
# and thus existing member attributes cannot be deduced by static analysis
ignored-modules=distutils,eventlet.green.subprocess,six,six.moves
# List of classes names for which member attributes should not be checked
# (useful for classes with attributes dynamically set).
# pylint is confused by sqlalchemy Table, as well as sqlalchemy Enum types
# ie: (unprovisioned, identity)
# LookupDict in requests library confuses pylint
ignored-classes=SQLObject, optparse.Values, thread._local, _thread._local,
Table, unprovisioned, identity, LookupDict
# List of members which are set dynamically and missed by pylint inference
# system, and so shouldn't trigger E0201 when accessed. Python regular
# expressions are accepted.
generated-members=REQUEST,acl_users,aq_parent
[BASIC]
# List of builtins function names that should not be used, separated by a comma
bad-functions=map,filter,apply,input
# Regular expression which should only match correct module names
module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
# Regular expression which should only match correct module level names
const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$
# Regular expression which should only match correct class names
class-rgx=[A-Z_][a-zA-Z0-9]+$
# Regular expression which should only match correct function names
function-rgx=[a-z_][a-z0-9_]{2,30}$
# Regular expression which should only match correct method names
method-rgx=[a-z_][a-z0-9_]{2,30}$
# Regular expression which should only match correct instance attribute names
attr-rgx=[a-z_][a-z0-9_]{2,30}$
# Regular expression which should only match correct argument names
argument-rgx=[a-z_][a-z0-9_]{2,30}$
# Regular expression which should only match correct variable names
variable-rgx=[a-z_][a-z0-9_]{2,30}$
# Regular expression which should only match correct list comprehension /
# generator expression variable names
inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
# Good variable names which should always be accepted, separated by a comma
good-names=i,j,k,ex,Run,_
# Bad variable names which should always be refused, separated by a comma
bad-names=foo,bar,baz,toto,tutu,tata
# Regular expression which should only match functions or classes name which do
# not require a docstring
no-docstring-rgx=__.*__
[MISCELLANEOUS]
# List of note tags to take in consideration, separated by a comma.
notes=FIXME,XXX,TODO
[VARIABLES]
# Tells whether we should check for unused import in __init__ files.
init-import=no
# A regular expression matching the beginning of the name of dummy variables
# (i.e. not used).
dummy-variables-rgx=_|dummy
# List of additional names supposed to be defined in builtins. Remember that
# you should avoid to define new builtins when possible.
additional-builtins=
[IMPORTS]
# Deprecated modules which should not be used, separated by a comma
deprecated-modules=regsub,string,TERMIOS,Bastion,rexec
# Create a graph of every (i.e. internal and external) dependencies in the
# given file (report RP0402 must not be disabled)
import-graph=
# Create a graph of external dependencies in the given file (report RP0402 must
# not be disabled)
ext-import-graph=
# Create a graph of internal dependencies in the given file (report RP0402 must
# not be disabled)
int-import-graph=
[DESIGN]
# Maximum number of arguments for function / method
max-args=5
# Argument names that match this expression will be ignored. Default to name
# with leading underscore
ignored-argument-names=_.*
# Maximum number of locals for function / method body
max-locals=15
# Maximum number of return / yield for function / method body
max-returns=6
# Maximum number of branch for function / method body
max-branchs=12
# Maximum number of statements in function / method body
max-statements=50
# Maximum number of parents for a class (see R0901).
max-parents=7
# Maximum number of attributes for a class (see R0902).
max-attributes=7
# Minimum number of public methods for a class (see R0903).
min-public-methods=2
# Maximum number of public methods for a class (see R0904).
max-public-methods=20
[CLASSES]
# List of method names used to declare (i.e. assign) instance attributes.
defining-attr-methods=__init__,__new__,setUp
# List of valid names for the first argument in a class method.
valid-classmethod-first-arg=cls
[EXCEPTIONS]
# Exceptions that will emit a warning when being caught. Defaults to
# "Exception"
overgeneral-exceptions=Exception

15
requirements.txt Normal file
View File

@ -0,0 +1,15 @@
httplib2
keystoneauth1
keystonemiddleware
oslo.config
oslo.db
oslo.log
oslo.policy
oslo.service
oslo.utils
oslo.versionedobjects
pecan
prettytable
pyOpenSSL
SQLAlchemy
WSME

View File

@ -1,5 +1,6 @@
hacking!=0.13.0,<0.14,>=0.12.0 hacking!=0.13.0,<0.14,>=0.12.0
bashate >= 0.2 bashate >= 0.2
mock
PyYAML >= 3.1.0 PyYAML >= 3.1.0
yamllint >= 0.5.2 yamllint >= 0.5.2
#spec_cleaner>=1.0.9 #spec_cleaner>=1.0.9

26
tox.ini
View File

@ -1,11 +1,13 @@
[tox] [tox]
envlist = linters,pep8,rpm-packaging-lint envlist = linters,pep8,pylint,rpm-packaging-lint
minversion = 2.3 minversion = 2.3
skipsdist = True skipsdist = True
stxdir = {toxinidir}/../ stxdir = {toxinidir}/../
[testenv] [testenv]
install_command = pip install -U {opts} {packages} install_command = pip install \
-chttps://opendev.org/openstack/requirements/raw/branch/stable/stein/upper-constraints.txt \
{opts} {packages}
setenv = VIRTUAL_ENV={envdir} setenv = VIRTUAL_ENV={envdir}
OS_STDOUT_CAPTURE=1 OS_STDOUT_CAPTURE=1
OS_STDERR_CAPTURE=1 OS_STDERR_CAPTURE=1
@ -17,9 +19,6 @@ basepython = python3
setenv = setenv =
VIRTUAL_ENV={envdir} VIRTUAL_ENV={envdir}
LC_ALL=en_US.utf-8 LC_ALL=en_US.utf-8
install_command = pip install -U \
-c{env:UPPER_CONSTRAINTS_FILE:https://opendev.org/openstack/requirements/raw/branch/stable/stein/upper-constraints.txt} \
{opts} {packages}
deps = -r{toxinidir}/test-requirements.txt deps = -r{toxinidir}/test-requirements.txt
whitelist_externals = bash whitelist_externals = bash
commands = commands =
@ -51,6 +50,23 @@ commands =
-o -type f -name '*.yaml' \ -o -type f -name '*.yaml' \
-print0 | xargs -0 yamllint -d '\{extends: relaxed, rules: \{line-length: \{max: 260\}\}\}'" -print0 | xargs -0 yamllint -d '\{extends: relaxed, rules: \{line-length: \{max: 260\}\}\}'"
[testenv:pylint]
basepython = python2.7
sitepackages = False
deps = {[testenv]deps}
-e{toxinidir}/../config/tsconfig/tsconfig
-e{toxinidir}/../config/sysinv/cgts-client/cgts-client
-r{toxinidir}/requirements.txt
pylint
commands = pylint {posargs} --rcfile=./pylint.rc \
fm-api/fm_api \
fm-common/sources/fm_db_sync_event_suppression.py \
fm-rest-api/fm/fm \
python-fmclient/fmclient/fmclient
#### ####
# Add flake8 as pep8 codestyle check. # Add flake8 as pep8 codestyle check.
[testenv:pep8] [testenv:pep8]