Compare commits

...

6 Commits
4.0.0 ... 4.0.1

Author SHA1 Message Date
Luigi Toscano
2e033d7b96 Native Zuul v3 watcher-grenade job + some cleanup
Create a native Zuul v3 grenade job. It matches the existing job,
even though it doesn't call any local hook as the current legacy
job does (because no local hook exists and it should be rewritten
as zuul configuration if it did).

The new job reuses the variable definition of the devstack watcher
job, so clean up that job as well:
- do not depend on devstack-gate, which is not needed and will be
  deprecated soon anyway;
- use the new way (tempest_plugins) to define which tempest plugin
  should be installed;
- remove the definition of USE_PYTHON3: true and simply inherit
  the value set by devstack;
- remove the definition of PYTHONUNBUFFERED, not really set
  anywhere else and only useful back in the days in Jenkins.

Change-Id: Ib0ed3c0f395e1b85b8f25f6e438c414165baab32
(cherry picked from commit ed59145354)
2020-08-06 10:32:17 +02:00
limin0801
0543ccfe74 Watcher API supports strategy name when creating audit template
when directly using the `curl` command to create audit template,
strategy name can be accepted.

Closes-Bug: #1884174

Change-Id: I7c0ca760a7fa414faca03c5293df34a84aad6fac
(cherry picked from commit 3f7a508a2e)
2020-07-10 01:15:40 +00:00
Zuul
ec62bbe5bd Merge "Compatible with old scope format" into stable/ussuri 2020-06-19 07:53:38 +00:00
licanwei
cbb06e6765 Check if scope is None
if scope is None, don't create data model

Change-Id: Icf611966c9b0a3882615d778ee6c72a8da73841d
Closed-Bug: #1881920
(cherry picked from commit 9f0138e1cf)
2020-06-19 01:46:15 +00:00
licanwei
6e1be3cca4 Compatible with old scope format
Scope format changed from old to new after bp cdm-scoping.

old format:
  - availability_zones:
    - name: nova
  - host_aggregates:
    - id: 1
    - name: agg
  - exclude:
    - compute_nodes:
      - name: w012

new format:
- compute:
  - availability_zones:
    - name: nova
  - host_aggregates:
    - id: 1
    - name: agg
  - exclude:
    - compute_nodes:
      - name: w012

Change-Id: I2b5cd4d1cee19f5588e4d2185eb074343fff1187
Closed-Bug: #1882049
(cherry picked from commit 4a1915bec4)
2020-06-11 02:15:25 +00:00
Chris MacNaughton
043ebb71c6 Monkey patch original current_thread _active
Monkey patch the original current_thread to use the up-to-date _active
global variable. This solution is based on that documented at:
https://github.com/eventlet/eventlet/issues/592

Change-Id: I194eedd505d45137963eb40d1b1d5da2309caeac
Closes-Bug: #1863021
(cherry picked from commit 0b4c4f1de6)
2020-05-15 09:25:40 +00:00
10 changed files with 123 additions and 98 deletions

View File

@@ -160,7 +160,6 @@
timeout: 7200
required-projects: &base_required_projects
- openstack/ceilometer
- openstack/devstack-gate
- openstack/python-openstackclient
- openstack/python-watcherclient
- openstack/watcher
@@ -179,14 +178,10 @@
s-container: false
s-object: false
s-proxy: false
devstack_localrc:
TEMPEST_PLUGINS: /opt/stack/watcher-tempest-plugin
USE_PYTHON3: true
tempest_plugins:
- watcher-tempest-plugin
tempest_test_regex: watcher_tempest_plugin.tests.api
tox_envlist: all
tox_environment:
# Do we really need to set this? It's cargo culted
PYTHONUNBUFFERED: 'true'
zuul_copy_output:
/etc/hosts: logs
@@ -200,10 +195,12 @@
- job:
name: watcher-grenade
parent: legacy-dsvm-base
timeout: 10800
run: playbooks/legacy/grenade-devstack-watcher/run.yaml
post-run: playbooks/legacy/grenade-devstack-watcher/post.yaml
parent: grenade
required-projects:
- openstack/watcher
- openstack/python-watcherclient
- openstack/watcher-tempest-plugin
vars: *base_vars
irrelevant-files:
- ^(test-|)requirements.txt$
- ^.*\.rst$
@@ -215,12 +212,6 @@
- ^setup.cfg$
- ^tools/.*$
- ^tox.ini$
required-projects:
- openstack/grenade
- openstack/devstack-gate
- openstack/watcher
- openstack/python-watcherclient
- openstack/watcher-tempest-plugin
- job:
# This job is used in python-watcherclient repo

View File

@@ -1,15 +0,0 @@
- hosts: primary
tasks:
- name: Copy files from {{ ansible_user_dir }}/workspace/ on node
synchronize:
src: '{{ ansible_user_dir }}/workspace/'
dest: '{{ zuul.executor.log_root }}'
mode: pull
copy_links: true
verify_host: true
rsync_opts:
- --include=/logs/**
- --include=*/
- --exclude=*
- --prune-empty-dirs

View File

@@ -1,60 +0,0 @@
- hosts: all
name: legacy-grenade-dsvm-watcher
tasks:
- name: Ensure legacy workspace directory
file:
path: '{{ ansible_user_dir }}/workspace'
state: directory
- shell:
cmd: |
set -e
set -x
cat > clonemap.yaml << EOF
clonemap:
- name: openstack/devstack-gate
dest: devstack-gate
EOF
/usr/zuul-env/bin/zuul-cloner -m clonemap.yaml --cache-dir /opt/git \
https://opendev.org \
openstack/devstack-gate
executable: /bin/bash
chdir: '{{ ansible_user_dir }}/workspace'
environment: '{{ zuul | zuul_legacy_vars }}'
- shell:
cmd: |
set -e
set -x
export PYTHONUNBUFFERED=true
export PROJECTS="openstack/grenade $PROJECTS"
export PROJECTS="openstack/watcher $PROJECTS"
export PROJECTS="openstack/watcher-tempest-plugin $PROJECTS"
export PROJECTS="openstack/python-watcherclient $PROJECTS"
export DEVSTACK_PROJECT_FROM_GIT="python-watcherclient $DEVSTACK_PROJECT_FROM_GIT"
export GRENADE_PLUGINRC="enable_grenade_plugin watcher https://opendev.org/openstack/watcher"
export DEVSTACK_LOCAL_CONFIG+=$'\n'"export TEMPEST_PLUGINS='/opt/stack/new/watcher-tempest-plugin'"
export DEVSTACK_GATE_TEMPEST_NOTESTS=1
export DEVSTACK_GATE_GRENADE=pullup
export DEVSTACK_GATE_USE_PYTHON3=True
export BRANCH_OVERRIDE=default
if [ "$BRANCH_OVERRIDE" != "default" ] ; then
export OVERRIDE_ZUUL_BRANCH=$BRANCH_OVERRIDE
fi
# Add configuration values for enabling security features in local.conf
function pre_test_hook {
if [ -f /opt/stack/old/watcher-tempest-plugin/tools/pre_test_hook.sh ] ; then
. /opt/stack/old/watcher-tempest-plugin/tools/pre_test_hook.sh
fi
}
export -f pre_test_hook
cp devstack-gate/devstack-vm-gate-wrap.sh ./safe-devstack-vm-gate-wrap.sh
./safe-devstack-vm-gate-wrap.sh
executable: /bin/bash
chdir: '{{ ansible_user_dir }}/workspace'
environment: '{{ zuul | zuul_legacy_vars }}'

View File

@@ -138,6 +138,9 @@ class AuditTemplatePostType(wtypes.Base):
raise exception.InvalidGoal(goal=audit_template.goal)
if audit_template.scope:
keys = [list(s)[0] for s in audit_template.scope]
if keys[0] not in ('compute', 'storage'):
audit_template.scope = [dict(compute=audit_template.scope)]
common_utils.Draft4Validator(
AuditTemplatePostType._build_schema()
).validate(audit_template.scope)
@@ -158,18 +161,23 @@ class AuditTemplatePostType(wtypes.Base):
"included and excluded together"))
if audit_template.strategy:
available_strategies = objects.Strategy.list(
AuditTemplatePostType._ctx)
available_strategies_map = {
s.uuid: s for s in available_strategies}
if audit_template.strategy not in available_strategies_map:
try:
if (common_utils.is_uuid_like(audit_template.strategy) or
common_utils.is_int_like(audit_template.strategy)):
strategy = objects.Strategy.get(
AuditTemplatePostType._ctx, audit_template.strategy)
else:
strategy = objects.Strategy.get_by_name(
AuditTemplatePostType._ctx, audit_template.strategy)
except Exception:
raise exception.InvalidStrategy(
strategy=audit_template.strategy)
strategy = available_strategies_map[audit_template.strategy]
# Check that the strategy we indicate is actually related to the
# specified goal
if strategy.goal_id != goal.id:
available_strategies = objects.Strategy.list(
AuditTemplatePostType._ctx)
choices = ["'%s' (%s)" % (s.uuid, s.name)
for s in available_strategies]
raise exception.InvalidStrategy(

View File

@@ -18,3 +18,10 @@
import eventlet
eventlet.monkey_patch()
# Monkey patch the original current_thread to use the up-to-date _active
# global variable. See https://bugs.launchpad.net/bugs/1863021 and
# https://github.com/eventlet/eventlet/issues/592
import __original_module_threading as orig_threading # noqa
import threading # noqa
orig_threading.current_thread.__globals__['_active'] = threading._active

View File

@@ -152,6 +152,9 @@ class CinderClusterDataModelCollector(base.BaseClusterDataModelCollector):
if self._audit_scope_handler is None:
LOG.debug("No audit, Don't Build storage data model")
return
if self._data_model_scope is None:
LOG.debug("No audit scope, Don't Build storage data model")
return
builder = CinderModelBuilder(self.osc)
return builder.execute(self._data_model_scope)

View File

@@ -63,6 +63,9 @@ class BaremetalClusterDataModelCollector(base.BaseClusterDataModelCollector):
if self._audit_scope_handler is None:
LOG.debug("No audit, Don't Build Baremetal data model")
return
if self._data_model_scope is None:
LOG.debug("No audit scope, Don't Build Baremetal data model")
return
builder = BareMetalModelBuilder(self.osc)
return builder.execute(self._data_model_scope)

View File

@@ -184,6 +184,9 @@ class NovaClusterDataModelCollector(base.BaseClusterDataModelCollector):
if self._audit_scope_handler is None:
LOG.debug("No audit, Don't Build compute data model")
return
if self._data_model_scope is None:
LOG.debug("No audit scope, Don't Build compute data model")
return
builder = NovaModelBuilder(self.osc)
return builder.execute(self._data_model_scope)

View File

@@ -555,6 +555,35 @@ class TestPost(FunctionalTestWithSetup):
response.json['created_at']).replace(tzinfo=None)
self.assertEqual(test_time, return_created_at)
@mock.patch.object(timeutils, 'utcnow')
def test_create_audit_template_with_strategy_name(self, mock_utcnow):
audit_template_dict = post_get_test_audit_template(
goal=self.fake_goal1.uuid,
strategy=self.fake_strategy1.name)
test_time = datetime.datetime(2000, 1, 1, 0, 0)
mock_utcnow.return_value = test_time
response = self.post_json('/audit_templates', audit_template_dict)
self.assertEqual('application/json', response.content_type)
self.assertEqual(201, response.status_int)
# Check location header
self.assertIsNotNone(response.location)
expected_location = \
'/v1/audit_templates/%s' % response.json['uuid']
self.assertEqual(urlparse.urlparse(response.location).path,
expected_location)
self.assertTrue(utils.is_uuid_like(response.json['uuid']))
self.assertNotIn('updated_at', response.json.keys)
self.assertNotIn('deleted_at', response.json.keys)
self.assertEqual(self.fake_goal1.uuid, response.json['goal_uuid'])
self.assertEqual(self.fake_strategy1.uuid,
response.json['strategy_uuid'])
self.assertEqual(self.fake_strategy1.name,
response.json['strategy_name'])
return_created_at = timeutils.parse_isotime(
response.json['created_at']).replace(tzinfo=None)
self.assertEqual(test_time, return_created_at)
def test_create_audit_template_validation_with_aggregates(self):
scope = [{'compute': [{'host_aggregates': [{'id': '*'}]},
{'availability_zones': [{'name': 'AZ1'},
@@ -663,6 +692,26 @@ class TestPost(FunctionalTestWithSetup):
self.assertEqual(400, response.status_int)
assert not cn_mock.called
def test_create_audit_template_with_old_scope(self):
scope = [{'host_aggregates': [{'id': '*'}]},
{'availability_zones': [{'name': 'AZ1'},
{'name': 'AZ2'}]},
{'exclude': [
{'instances': [
{'uuid': 'INSTANCE_1'},
{'uuid': 'INSTANCE_2'}]},
{'compute_nodes': [
{'name': 'Node_1'},
{'name': 'Node_2'}]},
]}
]
audit_template_dict = post_get_test_audit_template(
goal=self.fake_goal1.uuid,
strategy=self.fake_strategy1.uuid, scope=scope)
response = self.post_json('/audit_templates',
audit_template_dict)
self.assertEqual(201, response.status_int)
class TestDelete(api_base.FunctionalTest):

View File

@@ -17,6 +17,9 @@
import mock
from watcher.decision_engine.model.collector import base
from watcher.decision_engine.model.collector import cinder
from watcher.decision_engine.model.collector import ironic
from watcher.decision_engine.model.collector import nova
from watcher.decision_engine.model import model_root
from watcher.tests import base as test_base
@@ -55,3 +58,36 @@ class TestClusterDataModelCollector(test_base.TestCase):
self.assertIsNot(
collector.cluster_data_model,
collector.get_latest_cluster_data_model())
class TestComputeDataModelCollector(test_base.TestCase):
def test_model_scope_is_none(self):
m_config = mock.Mock()
collector = nova.NovaClusterDataModelCollector(config=m_config)
collector._audit_scope_handler = mock.Mock()
collector._data_model_scope = None
self.assertIsNone(collector.execute())
class TestStorageDataModelCollector(test_base.TestCase):
def test_model_scope_is_none(self):
m_config = mock.Mock()
collector = cinder.CinderClusterDataModelCollector(config=m_config)
collector._audit_scope_handler = mock.Mock()
collector._data_model_scope = None
self.assertIsNone(collector.execute())
class TestBareMetalDataModelCollector(test_base.TestCase):
def test_model_scope_is_none(self):
m_config = mock.Mock()
collector = ironic.BaremetalClusterDataModelCollector(config=m_config)
collector._audit_scope_handler = mock.Mock()
collector._data_model_scope = None
self.assertIsNone(collector.execute())