Compare commits

..

4 Commits

Author SHA1 Message Date
Thierry Carrez
ab64069e23 Move queue declaration to project level
This moves the watcher queue declaration from the pipeline level
(where it is no longer valid) to the project level.

https: //lists.openstack.org/pipermail/openstack-discuss/2022-May/028603.html
Change-Id: I06923abb00f7eecd59587f44cd1f6a069e88a9fc
(cherry picked from commit 6003322711)
2023-08-19 07:30:34 +00:00
OpenStack Release Bot
d8c7ad662f Update TOX_CONSTRAINTS_FILE for stable/victoria
Update the URL to the upper-constraints file to point to the redirect
rule on releases.openstack.org so that anyone working on this branch
will switch to the correct upper-constraints list automatically when
the requirements repository branches.

Until the requirements repository has as stable/victoria branch, tests will
continue to use the upper-constraints list on master.

Change-Id: Ieb0a95af10dd8e054254618a9021e69aca68191a
2020-09-30 01:54:48 +00:00
OpenStack Release Bot
9e3ce13f7b Update .gitreview for stable/victoria
Change-Id: I3314bd862a24fb5b114a562068168ef673b49397
2020-09-30 01:40:38 +00:00
Ghanshyam Mann
507765dc3e [goal] Migrate testing to ubuntu focal
As per victoria cycle testing runtime and community goal[1]
we need to migrate upstream CI/CD to Ubuntu Focal(20.04).

Fixing:
- bug#1886298
Bump the lower constraints for required deps which added python3.8 support
in their later version.

- Move multinode jobs to focal nodeset

Story: #2007865
Task: #40227

Closes-Bug: #1886298

[1] https://governance.openstack.org/tc/goals/selected/victoria/migrate-ci-cd-jobs-to-ubuntu-focal>

Depends-On: https://review.opendev.org/#/c/752294/

Change-Id: Iec953f3294087cd0b628b701ad3d684cea61c057
(cherry picked from commit e21e5f609e)
2020-09-29 09:02:47 +00:00
223 changed files with 2651 additions and 5281 deletions

View File

@@ -2,3 +2,4 @@
host=review.opendev.org host=review.opendev.org
port=29418 port=29418
project=openstack/watcher.git project=openstack/watcher.git
defaultbranch=stable/victoria

View File

@@ -1,62 +0,0 @@
---
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
# whitespace
- id: trailing-whitespace
- id: mixed-line-ending
args: ['--fix', 'lf']
exclude: '.*\.(svg)$'
- id: check-byte-order-marker
# file format and permissions
- id: check-ast
- id: debug-statements
- id: check-json
files: .*\.json$
- id: check-yaml
files: .*\.(yaml|yml)$
- id: check-executables-have-shebangs
- id: check-shebang-scripts-are-executable
# git
- id: check-added-large-files
- id: check-case-conflict
- id: detect-private-key
- id: check-merge-conflict
- repo: https://github.com/Lucas-C/pre-commit-hooks
rev: v1.5.5
hooks:
- id: remove-tabs
exclude: '.*\.(svg)$'
- repo: https://opendev.org/openstack/hacking
rev: 7.0.0
hooks:
- id: hacking
additional_dependencies: []
exclude: '^(doc|releasenotes|tools)/.*$'
- repo: https://github.com/PyCQA/bandit
rev: 1.7.6
hooks:
- id: bandit
args: ['-x', 'tests', '-s', 'B101,B311,B320']
- repo: https://github.com/hhatto/autopep8
rev: v2.3.1
hooks:
- id: autopep8
files: '^.*\.py$'
- repo: https://github.com/codespell-project/codespell
rev: v2.3.0
hooks:
- id: codespell
args: ['--ignore-words=doc/dictionary.txt']
- repo: https://github.com/sphinx-contrib/sphinx-lint
rev: v1.0.0
hooks:
- id: sphinx-lint
args: [--enable=default-role]
files: ^doc/|releasenotes|api-guide
types: [rst]
- repo: https://github.com/PyCQA/doc8
rev: v1.1.2
hooks:
- id: doc8

View File

@@ -3,31 +3,84 @@
templates: templates:
- check-requirements - check-requirements
- openstack-cover-jobs - openstack-cover-jobs
- openstack-python3-jobs - openstack-lower-constraints-jobs
- openstack-python3-victoria-jobs
- publish-openstack-docs-pti - publish-openstack-docs-pti
- release-notes-jobs-python3 - release-notes-jobs-python3
check: check:
jobs: jobs:
- watcher-tempest-functional - watcher-tempest-functional
- watcher-tempest-functional-jammy
- watcher-grenade - watcher-grenade
- watcher-tempest-strategies - watcher-tempest-strategies
- watcher-tempest-actuator - watcher-tempest-actuator
- watcherclient-tempest-functional - watcherclient-tempest-functional
- watcher-tls-test
- watcher-tempest-functional-ipv6-only - watcher-tempest-functional-ipv6-only
- watcher-prometheus-integration
gate: gate:
jobs: jobs:
- watcher-tempest-functional - watcher-tempest-functional
- watcher-tempest-functional-jammy
- watcher-tempest-functional-ipv6-only - watcher-tempest-functional-ipv6-only
- job:
name: watcher-tempest-dummy_optim
parent: watcher-tempest-multinode
vars:
tempest_test_regex: watcher_tempest_plugin.tests.scenario.test_execute_dummy_optim
- job: - job:
name: watcher-tempest-actuator name: watcher-tempest-actuator
parent: watcher-tempest-multinode parent: watcher-tempest-multinode
vars: vars:
tempest_test_regex: watcher_tempest_plugin.tests.scenario.test_execute_actuator tempest_test_regex: watcher_tempest_plugin.tests.scenario.test_execute_actuator
- job:
name: watcher-tempest-basic_optim
parent: watcher-tempest-multinode
vars:
tempest_test_regex: watcher_tempest_plugin.tests.scenario.test_execute_basic_optim
- job:
name: watcher-tempest-vm_workload_consolidation
parent: watcher-tempest-multinode
vars:
tempest_test_regex: watcher_tempest_plugin.tests.scenario.test_execute_vm_workload_consolidation
devstack_local_conf:
test-config:
$WATCHER_CONFIG:
watcher_strategies.vm_workload_consolidation:
datasource: ceilometer
- job:
name: watcher-tempest-workload_balancing
parent: watcher-tempest-multinode
vars:
tempest_test_regex: watcher_tempest_plugin.tests.scenario.test_execute_workload_balancing
- job:
name: watcher-tempest-zone_migration
parent: watcher-tempest-multinode
vars:
tempest_test_regex: watcher_tempest_plugin.tests.scenario.test_execute_zone_migration
- job:
name: watcher-tempest-host_maintenance
parent: watcher-tempest-multinode
vars:
tempest_test_regex: watcher_tempest_plugin.tests.scenario.test_execute_host_maintenance
- job:
name: watcher-tempest-storage_balance
parent: watcher-tempest-multinode
vars:
tempest_test_regex: watcher_tempest_plugin.tests.scenario.test_execute_storage_balance
devstack_local_conf:
test-config:
$TEMPEST_CONFIG:
volume:
backend_names: ['BACKEND_1', 'BACKEND_2']
volume-feature-enabled:
multi_backend: true
- job: - job:
name: watcher-tempest-strategies name: watcher-tempest-strategies
parent: watcher-tempest-multinode parent: watcher-tempest-multinode
@@ -35,10 +88,21 @@
tempest_concurrency: 1 tempest_concurrency: 1
tempest_test_regex: watcher_tempest_plugin.tests.scenario.test_execute_strategies tempest_test_regex: watcher_tempest_plugin.tests.scenario.test_execute_strategies
- job:
name: watcher-tls-test
parent: watcher-tempest-multinode
group-vars:
subnode:
devstack_services:
tls-proxy: true
vars:
devstack_services:
tls-proxy: true
- job: - job:
name: watcher-tempest-multinode name: watcher-tempest-multinode
parent: watcher-tempest-functional parent: watcher-tempest-functional
nodeset: openstack-two-node-noble nodeset: openstack-two-node-focal
roles: roles:
- zuul: openstack/tempest - zuul: openstack/tempest
group-vars: group-vars:
@@ -56,7 +120,8 @@
watcher-api: false watcher-api: false
watcher-decision-engine: true watcher-decision-engine: true
watcher-applier: false watcher-applier: false
c-bak: false # We need to add TLS support for watcher plugin
tls-proxy: false
ceilometer: false ceilometer: false
ceilometer-acompute: false ceilometer-acompute: false
ceilometer-acentral: false ceilometer-acentral: false
@@ -104,6 +169,7 @@
devstack_plugins: devstack_plugins:
watcher: https://opendev.org/openstack/watcher watcher: https://opendev.org/openstack/watcher
devstack_services: devstack_services:
tls-proxy: false
watcher-api: true watcher-api: true
watcher-decision-engine: true watcher-decision-engine: true
watcher-applier: true watcher-applier: true
@@ -119,17 +185,6 @@
zuul_copy_output: zuul_copy_output:
/etc/hosts: logs /etc/hosts: logs
# TODO(gmann): As per the 2025.1 testing runtime, we need to run at least
# one job on jammy. This job can be removed in the next cycle(2025.2)
- job:
name: watcher-tempest-functional-jammy
description: This is integrated job testing on Ubuntu jammy(22.04)
parent: watcher-tempest-functional
nodeset: openstack-single-node-jammy
vars:
<<: *base_vars
python_version: '3.9'
- job: - job:
name: watcher-tempest-functional-ipv6-only name: watcher-tempest-functional-ipv6-only
parent: devstack-tempest-ipv6 parent: devstack-tempest-ipv6
@@ -146,7 +201,7 @@
- openstack/python-watcherclient - openstack/python-watcherclient
- openstack/watcher-tempest-plugin - openstack/watcher-tempest-plugin
vars: *base_vars vars: *base_vars
irrelevant-files: &irrelevent_files irrelevant-files:
- ^(test-|)requirements.txt$ - ^(test-|)requirements.txt$
- ^.*\.rst$ - ^.*\.rst$
- ^api-ref/.*$ - ^api-ref/.*$
@@ -166,124 +221,3 @@
vars: vars:
tempest_concurrency: 1 tempest_concurrency: 1
tempest_test_regex: watcher_tempest_plugin.tests.client_functional tempest_test_regex: watcher_tempest_plugin.tests.client_functional
- job:
name: watcher-sg-core-tempest-base
parent: devstack-tempest
nodeset: openstack-two-node-noble
description: |
This job is for testing watcher and sg-core/prometheus installation
abstract: true
pre-run:
- playbooks/generate_prometheus_config.yml
irrelevant-files: *irrelevent_files
timeout: 7800
required-projects: &base_sg_required_projects
- openstack/aodh
- openstack/ceilometer
- openstack/tempest
- openstack-k8s-operators/sg-core
- openstack/watcher
- openstack/python-watcherclient
- openstack/watcher-tempest-plugin
- openstack/devstack-plugin-prometheus
vars:
configure_swap_size: 8192
devstack_plugins:
ceilometer: https://opendev.org/openstack/ceilometer
aodh: https://opendev.org/openstack/aodh
sg-core: https://github.com/openstack-k8s-operators/sg-core
watcher: https://opendev.org/openstack/watcher
devstack-plugin-prometheus: https://opendev.org/openstack/devstack-plugin-prometheus
devstack_services:
watcher-api: true
watcher-decision-engine: true
watcher-applier: true
tempest: true
# We do not need Swift in this job so disable it for speed
# Swift services
s-account: false
s-container: false
s-object: false
s-proxy: false
# Prometheus related service
prometheus: true
node_exporter: true
devstack_localrc:
CEILOMETER_BACKENDS: "sg-core"
CEILOMETER_PIPELINE_INTERVAL: 15
CEILOMETER_ALARM_THRESHOLD: 6000000000
NODE_EXPORTER_ENABLE: false
PROMETHEUS_ENABLE: false
PROMETHEUS_SERVICE_SCRAPE_TARGETS: "sg-core,node-exporter"
PROMETHEUS_CONFIG_FILE: "/home/zuul/prometheus.yml"
devstack_local_conf:
post-config:
$WATCHER_CONF:
watcher_datasources:
datasources: prometheus
prometheus_client:
host: 127.0.0.1
port: 9090
watcher_cluster_data_model_collectors.compute:
period: 120
watcher_cluster_data_model_collectors.baremetal:
period: 120
watcher_cluster_data_model_collectors.storage:
period: 120
test-config:
$TEMPEST_CONFIG:
compute:
min_compute_nodes: 2
min_microversion: 2.56
compute-feature-enabled:
live_migration: true
block_migration_for_live_migration: true
placement:
min_microversion: 1.29
service_available:
sg_core: True
telemetry_services:
metric_backends: prometheus
telemetry:
disable_ssl_certificate_validation: True
ceilometer_polling_interval: 15
optimize:
datasource: prometheus
tempest_plugins:
- watcher-tempest-plugin
tempest_test_regex: watcher_tempest_plugin.tests.scenario.test_execute_strategies
tempest_concurrency: 1
tox_envlist: all
zuul_copy_output:
/etc/prometheus/prometheus.yml: logs
group-vars:
subnode:
devstack_plugins:
ceilometer: https://opendev.org/openstack/ceilometer
sg-core: https://github.com/openstack-k8s-operators/sg-core
devstack-plugin-prometheus: https://opendev.org/openstack/devstack-plugin-prometheus
devstack_services:
ceilometer-acompute: true
sg-core: false
prometheus: false
node_exporter: true
devstack_localrc:
CEILOMETER_BACKEND: "none"
CEILOMETER_BACKENDS: "none"
# sg_core related var
NODE_EXPORTER_ENABLE: false
PROMETHEUS_ENABLE: false
devstack_local_conf:
post-config:
$WATCHER_CONF:
watcher_cluster_data_model_collectors.compute:
period: 120
watcher_cluster_data_model_collectors.baremetal:
period: 120
watcher_cluster_data_model_collectors.storage:
period: 120
- job:
name: watcher-prometheus-integration
parent: watcher-sg-core-tempest-base

View File

@@ -30,7 +30,7 @@
} }
}, },
"auto_trigger": false, "auto_trigger": false,
"force": false, "force": false,
"uuid": "65a5da84-5819-4aea-8278-a28d2b489028", "uuid": "65a5da84-5819-4aea-8278-a28d2b489028",
"goal_name": "workload_balancing", "goal_name": "workload_balancing",
"scope": [], "scope": [],

View File

@@ -13,9 +13,9 @@
"node_vcpu_ratio": "16.0", "node_vcpu_ratio": "16.0",
"node_memory": "16383", "node_memory": "16383",
"node_memory_ratio": "1.5", "node_memory_ratio": "1.5",
"node_disk": "37", "node_disk": "37"
"node_disk_ratio": "1.0", "node_disk_ratio": "1.0",
"node_state": "up" "node_state": "up",
}, },
{ {
"server_uuid": "e2cb5f6f-fa1d-4ba2-be1e-0bf02fa86ba4", "server_uuid": "e2cb5f6f-fa1d-4ba2-be1e-0bf02fa86ba4",
@@ -30,9 +30,9 @@
"node_vcpu_ratio": "16.0", "node_vcpu_ratio": "16.0",
"node_memory": "16383", "node_memory": "16383",
"node_memory_ratio": "1.5", "node_memory_ratio": "1.5",
"node_disk": "37", "node_disk": "37"
"node_disk_ratio": "1.0", "node_disk_ratio": "1.0",
"node_state": "up" "node_state": "up",
} }
] ]
} }

View File

@@ -12,7 +12,7 @@ Here are some examples of ``Goals``:
- minimize the energy consumption - minimize the energy consumption
- minimize the number of compute nodes (consolidation) - minimize the number of compute nodes (consolidation)
- balance the workload among compute nodes - balance the workload among compute nodes
- minimize the license cost (some software have a licensing model which is - minimize the license cost (some softwares have a licensing model which is
based on the number of sockets or cores where the software is deployed) based on the number of sockets or cores where the software is deployed)
- find the most appropriate moment for a planned maintenance on a - find the most appropriate moment for a planned maintenance on a
given group of host (which may be an entire availability zone): given group of host (which may be an entire availability zone):
@@ -123,4 +123,4 @@ Response
**Example JSON representation of a Goal:** **Example JSON representation of a Goal:**
.. literalinclude:: samples/goal-show-response.json .. literalinclude:: samples/goal-show-response.json
:language: javascript :language: javascript

View File

@@ -1,3 +1,5 @@
#!/bin/bash
#
# lib/watcher # lib/watcher
# Functions to control the configuration and operation of the watcher services # Functions to control the configuration and operation of the watcher services
@@ -36,6 +38,7 @@ GITBRANCH["python-watcherclient"]=${WATCHERCLIENT_BRANCH:-master}
GITDIR["python-watcherclient"]=$DEST/python-watcherclient GITDIR["python-watcherclient"]=$DEST/python-watcherclient
WATCHER_STATE_PATH=${WATCHER_STATE_PATH:=$DATA_DIR/watcher} WATCHER_STATE_PATH=${WATCHER_STATE_PATH:=$DATA_DIR/watcher}
WATCHER_AUTH_CACHE_DIR=${WATCHER_AUTH_CACHE_DIR:-/var/cache/watcher}
WATCHER_CONF_DIR=/etc/watcher WATCHER_CONF_DIR=/etc/watcher
WATCHER_CONF=$WATCHER_CONF_DIR/watcher.conf WATCHER_CONF=$WATCHER_CONF_DIR/watcher.conf
@@ -100,7 +103,7 @@ function _cleanup_watcher_apache_wsgi {
# cleanup_watcher() - Remove residual data files, anything left over from previous # cleanup_watcher() - Remove residual data files, anything left over from previous
# runs that a clean run would need to clean up # runs that a clean run would need to clean up
function cleanup_watcher { function cleanup_watcher {
sudo rm -rf $WATCHER_STATE_PATH sudo rm -rf $WATCHER_STATE_PATH $WATCHER_AUTH_CACHE_DIR
if [[ "$WATCHER_USE_WSGI_MODE" == "uwsgi" ]]; then if [[ "$WATCHER_USE_WSGI_MODE" == "uwsgi" ]]; then
remove_uwsgi_config "$WATCHER_UWSGI_CONF" "$WATCHER_UWSGI" remove_uwsgi_config "$WATCHER_UWSGI_CONF" "$WATCHER_UWSGI"
else else
@@ -207,8 +210,8 @@ function create_watcher_conf {
iniset $WATCHER_CONF oslo_messaging_notifications driver "messagingv2" iniset $WATCHER_CONF oslo_messaging_notifications driver "messagingv2"
configure_keystone_authtoken_middleware $WATCHER_CONF watcher configure_auth_token_middleware $WATCHER_CONF watcher $WATCHER_AUTH_CACHE_DIR
configure_keystone_authtoken_middleware $WATCHER_CONF watcher "watcher_clients_auth" configure_auth_token_middleware $WATCHER_CONF watcher $WATCHER_AUTH_CACHE_DIR "watcher_clients_auth"
if is_fedora || is_suse; then if is_fedora || is_suse; then
# watcher defaults to /usr/local/bin, but fedora and suse pip like to # watcher defaults to /usr/local/bin, but fedora and suse pip like to
@@ -245,6 +248,13 @@ function create_watcher_conf {
fi fi
} }
# create_watcher_cache_dir() - Part of the init_watcher() process
function create_watcher_cache_dir {
# Create cache dir
sudo install -d -o $STACK_USER $WATCHER_AUTH_CACHE_DIR
rm -rf $WATCHER_AUTH_CACHE_DIR/*
}
# init_watcher() - Initialize databases, etc. # init_watcher() - Initialize databases, etc.
function init_watcher { function init_watcher {
# clean up from previous (possibly aborted) runs # clean up from previous (possibly aborted) runs
@@ -256,6 +266,7 @@ function init_watcher {
# Create watcher schema # Create watcher schema
$WATCHER_BIN_DIR/watcher-db-manage --config-file $WATCHER_CONF upgrade $WATCHER_BIN_DIR/watcher-db-manage --config-file $WATCHER_CONF upgrade
fi fi
create_watcher_cache_dir
} }
# install_watcherclient() - Collect source and prepare # install_watcherclient() - Collect source and prepare
@@ -264,9 +275,6 @@ function install_watcherclient {
git_clone_by_name "python-watcherclient" git_clone_by_name "python-watcherclient"
setup_dev_lib "python-watcherclient" setup_dev_lib "python-watcherclient"
fi fi
if [[ "$GLOBAL_VENV" == "True" ]]; then
sudo ln -sf /opt/stack/data/venv/bin/watcher /usr/local/bin
fi
} }
# install_watcher() - Collect source and prepare # install_watcher() - Collect source and prepare

View File

@@ -1,3 +1,5 @@
#!/bin/bash
#
# plugin.sh - DevStack plugin script to install watcher # plugin.sh - DevStack plugin script to install watcher
# Save trace setting # Save trace setting

View File

@@ -1,3 +1,5 @@
#!/usr/bin/env bash
# ``upgrade-watcher`` # ``upgrade-watcher``
function configure_watcher_upgrade { function configure_watcher_upgrade {

View File

@@ -70,7 +70,7 @@ then write_uwsgi_config "$WATCHER_UWSGI_CONF" "$WATCHER_UWSGI" "/infra-optim"
fi fi
# Migrate the database # Migrate the database
$WATCHER_BIN_DIR/watcher-db-manage upgrade || die $LINO "DB migration error" watcher-db-manage upgrade || die $LINO "DB migration error"
start_watcher start_watcher

View File

@@ -1,4 +0,0 @@
thirdparty
assertin
notin

View File

@@ -52,7 +52,7 @@ class BaseWatcherDirective(rst.Directive):
obj_raw_docstring = obj.__init__.__doc__ obj_raw_docstring = obj.__init__.__doc__
if not obj_raw_docstring: if not obj_raw_docstring:
# Raise a warning to make the tests fail with doc8 # Raise a warning to make the tests fail wit doc8
raise self.error("No docstring available for %s!" % obj) raise self.error("No docstring available for %s!" % obj)
obj_docstring = inspect.cleandoc(obj_raw_docstring) obj_docstring = inspect.cleandoc(obj_raw_docstring)

View File

@@ -1,10 +1,10 @@
sphinx>=2.1.1 # BSD # The order of packages is significant, because pip processes them in the order
sphinxcontrib-svg2pdfconverter>=0.1.0 # BSD # of appearance. Changing the order has an impact on the overall integration
sphinxcontrib-pecanwsme>=0.8.0 # Apache-2.0 # process, which may cause wedges in the gate later.
sphinxcontrib-apidoc>=0.2.0 # BSD
# openstack
os-api-ref>=1.4.0 # Apache-2.0
openstackdocstheme>=2.2.1 # Apache-2.0 openstackdocstheme>=2.2.1 # Apache-2.0
# releasenotes sphinx>=2.0.0,!=2.1.0 # BSD
sphinxcontrib-pecanwsme>=0.8.0 # Apache-2.0
sphinxcontrib-svg2pdfconverter>=0.1.0 # BSD
reno>=3.1.0 # Apache-2.0 reno>=3.1.0 # Apache-2.0
sphinxcontrib-apidoc>=0.2.0 # BSD
os-api-ref>=1.4.0 # Apache-2.0

View File

@@ -34,7 +34,7 @@ own sections. However, the base *GMR* consists of several sections:
Package Package
Shows information about the package to which this process belongs, including Shows information about the package to which this process belongs, including
version information. version informations.
Threads Threads
Shows stack traces and thread ids for each of the threads within this Shows stack traces and thread ids for each of the threads within this

View File

@@ -17,14 +17,6 @@
Policies Policies
======== ========
.. warning::
JSON formatted policy file is deprecated since Watcher 6.0.0 (Wallaby).
This `oslopolicy-convert-json-to-yaml`__ tool will migrate your existing
JSON-formatted policy file to YAML in a backward-compatible way.
.. __: https://docs.openstack.org/oslo.policy/latest/cli/oslopolicy-convert-json-to-yaml.html
Watcher's public API calls may be restricted to certain sets of users using a Watcher's public API calls may be restricted to certain sets of users using a
policy configuration file. This document explains exactly how policies are policy configuration file. This document explains exactly how policies are
configured and what they apply to. configured and what they apply to.

View File

@@ -285,7 +285,7 @@ Audit and interval (in case of CONTINUOUS type). There is three types of Audit:
ONESHOT, CONTINUOUS and EVENT. ONESHOT Audit is launched once and if it ONESHOT, CONTINUOUS and EVENT. ONESHOT Audit is launched once and if it
succeeded executed new action plan list will be provided; CONTINUOUS Audit succeeded executed new action plan list will be provided; CONTINUOUS Audit
creates action plans with specified interval (in seconds or cron format, cron creates action plans with specified interval (in seconds or cron format, cron
interval can be used like: ``*/5 * * * *``), if action plan inteval can be used like: `*/5 * * * *`), if action plan
has been created, all previous action plans get CANCELLED state; has been created, all previous action plans get CANCELLED state;
EVENT audit is launched when receiving webhooks API. EVENT audit is launched when receiving webhooks API.

22
doc/source/conf.py Normal file → Executable file
View File

@@ -56,8 +56,8 @@ source_suffix = '.rst'
master_doc = 'index' master_doc = 'index'
# General information about the project. # General information about the project.
project = 'Watcher' project = u'Watcher'
copyright = 'OpenStack Foundation' copyright = u'OpenStack Foundation'
# A list of ignored prefixes for module index sorting. # A list of ignored prefixes for module index sorting.
modindex_common_prefix = ['watcher.'] modindex_common_prefix = ['watcher.']
@@ -91,14 +91,14 @@ pygments_style = 'native'
# List of tuples 'sourcefile', 'target', u'title', u'Authors name', 'manual' # List of tuples 'sourcefile', 'target', u'title', u'Authors name', 'manual'
man_pages = [ man_pages = [
('man/watcher-api', 'watcher-api', 'Watcher API Server', ('man/watcher-api', 'watcher-api', u'Watcher API Server',
['OpenStack'], 1), [u'OpenStack'], 1),
('man/watcher-applier', 'watcher-applier', 'Watcher Applier', ('man/watcher-applier', 'watcher-applier', u'Watcher Applier',
['OpenStack'], 1), [u'OpenStack'], 1),
('man/watcher-db-manage', 'watcher-db-manage', ('man/watcher-db-manage', 'watcher-db-manage',
'Watcher Db Management Utility', ['OpenStack'], 1), u'Watcher Db Management Utility', [u'OpenStack'], 1),
('man/watcher-decision-engine', 'watcher-decision-engine', ('man/watcher-decision-engine', 'watcher-decision-engine',
'Watcher Decision Engine', ['OpenStack'], 1), u'Watcher Decision Engine', [u'OpenStack'], 1),
] ]
# -- Options for HTML output -------------------------------------------------- # -- Options for HTML output --------------------------------------------------
@@ -115,7 +115,7 @@ html_theme = 'openstackdocs'
htmlhelp_basename = '%sdoc' % project htmlhelp_basename = '%sdoc' % project
# openstackdocstheme options #openstackdocstheme options
openstackdocs_repo_name = 'openstack/watcher' openstackdocs_repo_name = 'openstack/watcher'
openstackdocs_pdf_link = True openstackdocs_pdf_link = True
openstackdocs_auto_name = False openstackdocs_auto_name = False
@@ -128,8 +128,8 @@ openstackdocs_bug_tag = ''
latex_documents = [ latex_documents = [
('index', ('index',
'doc-watcher.tex', 'doc-watcher.tex',
'Watcher Documentation', u'Watcher Documentation',
'OpenStack Foundation', 'manual'), u'OpenStack Foundation', 'manual'),
] ]
# If false, no module index is generated. # If false, no module index is generated.

View File

@@ -194,14 +194,11 @@ The configuration file is organized into the following sections:
* ``[watcher_applier]`` - Watcher Applier module configuration * ``[watcher_applier]`` - Watcher Applier module configuration
* ``[watcher_decision_engine]`` - Watcher Decision Engine module configuration * ``[watcher_decision_engine]`` - Watcher Decision Engine module configuration
* ``[oslo_messaging_rabbit]`` - Oslo Messaging RabbitMQ driver configuration * ``[oslo_messaging_rabbit]`` - Oslo Messaging RabbitMQ driver configuration
* ``[ceilometer_client]`` - Ceilometer client configuration
* ``[cinder_client]`` - Cinder client configuration * ``[cinder_client]`` - Cinder client configuration
* ``[glance_client]`` - Glance client configuration * ``[glance_client]`` - Glance client configuration
* ``[gnocchi_client]`` - Gnocchi client configuration
* ``[ironic_client]`` - Ironic client configuration
* ``[keystone_client]`` - Keystone client configuration
* ``[nova_client]`` - Nova client configuration * ``[nova_client]`` - Nova client configuration
* ``[neutron_client]`` - Neutron client configuration * ``[neutron_client]`` - Neutron client configuration
* ``[placement_client]`` - Placement client configuration
The Watcher configuration file is expected to be named The Watcher configuration file is expected to be named
``watcher.conf``. When starting Watcher, you can specify a different ``watcher.conf``. When starting Watcher, you can specify a different
@@ -375,7 +372,7 @@ You can configure and install Ceilometer by following the documentation below :
#. https://docs.openstack.org/ceilometer/latest #. https://docs.openstack.org/ceilometer/latest
The built-in strategy 'basic_consolidation' provided by watcher requires The built-in strategy 'basic_consolidation' provided by watcher requires
"**compute.node.cpu.percent**" and "**cpu**" measurements to be collected "**compute.node.cpu.percent**" and "**cpu_util**" measurements to be collected
by Ceilometer. by Ceilometer.
The measurements available depend on the hypervisors that OpenStack manages on The measurements available depend on the hypervisors that OpenStack manages on
the specific implementation. the specific implementation.

View File

@@ -221,7 +221,7 @@ workflow engine can halt or take other actions while the action plan is being
executed based on the success or failure of individual actions. However, the executed based on the success or failure of individual actions. However, the
base workflow engine simply uses these notifies to store the result of base workflow engine simply uses these notifies to store the result of
individual actions in the database. Additionally, since taskflow uses a graph individual actions in the database. Additionally, since taskflow uses a graph
flow if any of the tasks would fail all children of this tasks not be executed flow if any of the tasks would fail all childs of this tasks not be executed
while ``do_revert`` will be triggered for all parents. while ``do_revert`` will be triggered for all parents.
.. code-block:: python .. code-block:: python

View File

@@ -16,7 +16,7 @@ multinode environment to use.
You can set up the Watcher services quickly and easily using a Watcher You can set up the Watcher services quickly and easily using a Watcher
DevStack plugin. See `PluginModelDocs`_ for information on DevStack's plugin DevStack plugin. See `PluginModelDocs`_ for information on DevStack's plugin
model. To enable the Watcher plugin with DevStack, add the following to the model. To enable the Watcher plugin with DevStack, add the following to the
``[[local|localrc]]`` section of your controller's ``local.conf`` to enable the `[[local|localrc]]` section of your controller's `local.conf` to enable the
Watcher plugin:: Watcher plugin::
enable_plugin watcher https://opendev.org/openstack/watcher enable_plugin watcher https://opendev.org/openstack/watcher
@@ -32,7 +32,7 @@ Quick Devstack Instructions with Datasources
Watcher requires a datasource to collect metrics from compute nodes and Watcher requires a datasource to collect metrics from compute nodes and
instances in order to execute most strategies. To enable this a instances in order to execute most strategies. To enable this a
``[[local|localrc]]`` to setup DevStack for some of the supported datasources `[[local|localrc]]` to setup DevStack for some of the supported datasources
is provided. These examples specify the minimal configuration parameters to is provided. These examples specify the minimal configuration parameters to
get both Watcher and the datasource working but can be expanded is desired. get both Watcher and the datasource working but can be expanded is desired.
@@ -41,60 +41,52 @@ Gnocchi
With the Gnocchi datasource most of the metrics for compute nodes and With the Gnocchi datasource most of the metrics for compute nodes and
instances will work with the provided configuration but metrics that instances will work with the provided configuration but metrics that
require Ironic such as ``host_airflow and`` ``host_power`` will still be require Ironic such as `host_airflow and` `host_power` will still be
unavailable as well as ``instance_l3_cpu_cache`` unavailable as well as `instance_l3_cpu_cache`::
.. code-block:: ini [[local|localrc]]
enable_plugin watcher https://opendev.org/openstack/watcher
[[local|localrc]] enable_plugin ceilometer https://opendev.org/openstack/ceilometer.git
CEILOMETER_BACKEND=gnocchi
enable_plugin watcher https://opendev.org/openstack/watcher enable_plugin aodh https://opendev.org/openstack/aodh
enable_plugin watcher-dashboard https://opendev.org/openstack/watcher-dashboard enable_plugin panko https://opendev.org/openstack/panko
enable_plugin ceilometer https://opendev.org/openstack/ceilometer.git
enable_plugin aodh https://opendev.org/openstack/aodh
enable_plugin panko https://opendev.org/openstack/panko
CEILOMETER_BACKEND=gnocchi [[post-config|$NOVA_CONF]]
[[post-config|$NOVA_CONF]] [DEFAULT]
[DEFAULT] compute_monitors=cpu.virt_driver
compute_monitors=cpu.virt_driver
Detailed DevStack Instructions Detailed DevStack Instructions
============================== ==============================
#. Obtain N (where N >= 1) servers (virtual machines preferred for DevStack). #. Obtain N (where N >= 1) servers (virtual machines preferred for DevStack).
One of these servers will be the controller node while the others will be One of these servers will be the controller node while the others will be
compute nodes. N is preferably >= 3 so that you have at least 2 compute compute nodes. N is preferably >= 3 so that you have at least 2 compute
nodes, but in order to stand up the Watcher services only 1 server is nodes, but in order to stand up the Watcher services only 1 server is
needed (i.e., no computes are needed if you want to just experiment with needed (i.e., no computes are needed if you want to just experiment with
the Watcher services). These servers can be VMs running on your local the Watcher services). These servers can be VMs running on your local
machine via VirtualBox if you prefer. DevStack currently recommends that machine via VirtualBox if you prefer. DevStack currently recommends that
you use Ubuntu 16.04 LTS. The servers should also have connections to the you use Ubuntu 16.04 LTS. The servers should also have connections to the
same network such that they are all able to communicate with one another. same network such that they are all able to communicate with one another.
#. For each server, clone the DevStack repository and create the stack user #. For each server, clone the DevStack repository and create the stack user::
.. code-block:: bash sudo apt-get update
sudo apt-get install git
sudo apt-get update git clone https://opendev.org/openstack/devstack.git
sudo apt-get install git sudo ./devstack/tools/create-stack-user.sh
git clone https://opendev.org/openstack/devstack.git
sudo ./devstack/tools/create-stack-user.sh
Now you have a stack user that is used to run the DevStack processes. You Now you have a stack user that is used to run the DevStack processes. You
may want to give your stack user a password to allow SSH via a password may want to give your stack user a password to allow SSH via a password::
.. code-block:: bash sudo passwd stack
sudo passwd stack #. Switch to the stack user and clone the DevStack repo again::
#. Switch to the stack user and clone the DevStack repo again sudo su stack
cd ~
.. code-block:: bash git clone https://opendev.org/openstack/devstack.git
sudo su stack
cd ~
git clone https://opendev.org/openstack/devstack.git
#. For each compute node, copy the provided `local.conf.compute`_ example file #. For each compute node, copy the provided `local.conf.compute`_ example file
to the compute node's system at ~/devstack/local.conf. Make sure the to the compute node's system at ~/devstack/local.conf. Make sure the
@@ -117,30 +109,24 @@ Detailed DevStack Instructions
the HOST_IP value is changed appropriately - i.e., HOST_IP is set to the IP the HOST_IP value is changed appropriately - i.e., HOST_IP is set to the IP
address of the controller node. address of the controller node.
.. NOTE:: Note: if you want to use another Watcher git repository (such as a local
if you want to use another Watcher git repository (such as a local one), then change the enable plugin line::
one), then change the enable plugin line
.. code-block:: bash
enable_plugin watcher <your_local_git_repo> [optional_branch]
enable_plugin watcher <your_local_git_repo> [optional_branch]
If you do this, then the Watcher DevStack plugin will try to pull the If you do this, then the Watcher DevStack plugin will try to pull the
python-watcherclient repo from ``<your_local_git_repo>/../``, so either make python-watcherclient repo from <your_local_git_repo>/../, so either make
sure that is also available or specify WATCHERCLIENT_REPO in the ``local.conf`` sure that is also available or specify WATCHERCLIENT_REPO in the local.conf
file. file.
.. NOTE:: Note: if you want to use a specific branch, specify WATCHER_BRANCH in the
if you want to use a specific branch, specify WATCHER_BRANCH in the local.conf file. By default it will use the master branch.
local.conf file. By default it will use the master branch.
.. Note:: Note: watcher-api will default run under apache/httpd, set the variable
watcher-api will default run under apache/httpd, set the variable WATCHER_USE_MOD_WSGI=FALSE if you do not wish to run under apache/httpd.
WATCHER_USE_MOD_WSGI=FALSE if you do not wish to run under apache/httpd. For development environment it is suggested to set WATHCER_USE_MOD_WSGI
For development environment it is suggested to set WATHCER_USE_MOD_WSGI to FALSE. For Production environment it is suggested to keep it at the
to FALSE. For Production environment it is suggested to keep it at the default TRUE value.
default TRUE value.
#. Start stacking from the controller node:: #. Start stacking from the controller node::
@@ -148,9 +134,8 @@ Detailed DevStack Instructions
#. Start stacking on each of the compute nodes using the same command. #. Start stacking on each of the compute nodes using the same command.
.. seealso:: #. Configure the environment for live migration via NFS. See the
Configure the environment for live migration via NFS. See the `Multi-Node DevStack Environment`_ section for more details.
`Multi-Node DevStack Environment`_ section for more details.
.. _local.conf.controller: https://github.com/openstack/watcher/tree/master/devstack/local.conf.controller .. _local.conf.controller: https://github.com/openstack/watcher/tree/master/devstack/local.conf.controller
.. _local.conf.compute: https://github.com/openstack/watcher/tree/master/devstack/local.conf.compute .. _local.conf.compute: https://github.com/openstack/watcher/tree/master/devstack/local.conf.compute
@@ -162,19 +147,60 @@ Since deploying Watcher with only a single compute node is not very useful, a
few tips are given here for enabling a multi-node environment with live few tips are given here for enabling a multi-node environment with live
migration. migration.
.. NOTE:: Configuring NFS Server
----------------------
Nova supports live migration with local block storage so by default NFS If you would like to use live migration for shared storage, then the controller
is not required and is considered an advance configuration. can serve as the NFS server if needed::
The minimum requirements for live migration are:
- all hostnames are resolvable on each host sudo apt-get install nfs-kernel-server
- all hosts have a passwordless ssh key that is trusted by the other hosts sudo mkdir -p /nfs/instances
- all hosts have a known_hosts file that lists each hosts sudo chown stack:stack /nfs/instances
If these requirements are met live migration will be possible. Add an entry to `/etc/exports` with the appropriate gateway and netmask
Shared storage such as ceph, booting form cinder volume or nfs are recommend information::
when testing evacuate if you want to preserve vm data.
/nfs/instances <gateway>/<netmask>(rw,fsid=0,insecure,no_subtree_check,async,no_root_squash)
Export the NFS directories::
sudo exportfs -ra
Make sure the NFS server is running::
sudo service nfs-kernel-server status
If the server is not running, then start it::
sudo service nfs-kernel-server start
Configuring NFS on Compute Node
-------------------------------
Each compute node needs to use the NFS server to hold the instance data::
sudo apt-get install rpcbind nfs-common
mkdir -p /opt/stack/data/instances
sudo mount <nfs-server-ip>:/nfs/instances /opt/stack/data/instances
If you would like to have the NFS directory automatically mounted on reboot,
then add the following to `/etc/fstab`::
<nfs-server-ip>:/nfs/instances /opt/stack/data/instances nfs auto 0 0
Edit `/etc/libvirt/libvirtd.conf` to make sure the following values are set::
listen_tls = 0
listen_tcp = 1
auth_tcp = "none"
Edit `/etc/default/libvirt-bin`::
libvirtd_opts="-d -l"
Restart the libvirt service::
sudo service libvirt-bin restart
Setting up SSH keys between compute nodes to enable live migration Setting up SSH keys between compute nodes to enable live migration
------------------------------------------------------------------ ------------------------------------------------------------------
@@ -203,91 +229,22 @@ must exist in every other compute node's stack user's authorized_keys file and
every compute node's public ECDSA key needs to be in every other compute every compute node's public ECDSA key needs to be in every other compute
node's root user's known_hosts file. node's root user's known_hosts file.
Configuring NFS Server (ADVANCED) Disable serial console
--------------------------------- ----------------------
If you would like to use live migration for shared storage, then the controller Serial console needs to be disabled for live migration to work.
can serve as the NFS server if needed
.. code-block:: bash On both the controller and compute node, in /etc/nova/nova.conf
sudo apt-get install nfs-kernel-server [serial_console]
sudo mkdir -p /nfs/instances enabled = False
sudo chown stack:stack /nfs/instances
Add an entry to ``/etc/exports`` with the appropriate gateway and netmask Alternatively, in devstack's local.conf:
information
[[post-config|$NOVA_CONF]]
[serial_console]
#enabled=false
.. code-block:: bash
/nfs/instances <gateway>/<netmask>(rw,fsid=0,insecure,no_subtree_check,async,no_root_squash)
Export the NFS directories
.. code-block:: bash
sudo exportfs -ra
Make sure the NFS server is running
.. code-block:: bash
sudo service nfs-kernel-server status
If the server is not running, then start it
.. code-block:: bash
sudo service nfs-kernel-server start
Configuring NFS on Compute Node (ADVANCED)
------------------------------------------
Each compute node needs to use the NFS server to hold the instance data
.. code-block:: bash
sudo apt-get install rpcbind nfs-common
mkdir -p /opt/stack/data/instances
sudo mount <nfs-server-ip>:/nfs/instances /opt/stack/data/instances
If you would like to have the NFS directory automatically mounted on reboot,
then add the following to ``/etc/fstab``
.. code-block:: bash
<nfs-server-ip>:/nfs/instances /opt/stack/data/instances nfs auto 0 0
Configuring libvirt to listen on tcp (ADVANCED)
-----------------------------------------------
.. NOTE::
By default nova will use ssh as a transport for live migration
if you have a low bandwidth connection you can use tcp instead
however this is generally not recommended.
Edit ``/etc/libvirt/libvirtd.conf`` to make sure the following values are set
.. code-block:: ini
listen_tls = 0
listen_tcp = 1
auth_tcp = "none"
Edit ``/etc/default/libvirt-bin``
.. code-block:: ini
libvirtd_opts="-d -l"
Restart the libvirt service
.. code-block:: bash
sudo service libvirt-bin restart
VNC server configuration VNC server configuration
------------------------ ------------------------
@@ -295,18 +252,13 @@ VNC server configuration
The VNC server listening parameter needs to be set to any address so The VNC server listening parameter needs to be set to any address so
that the server can accept connections from all of the compute nodes. that the server can accept connections from all of the compute nodes.
On both the controller and compute node, in ``/etc/nova/nova.conf`` On both the controller and compute node, in /etc/nova/nova.conf
.. code-block:: ini vncserver_listen = 0.0.0.0
[vnc] Alternatively, in devstack's local.conf:
server_listen = "0.0.0.0"
Alternatively, in devstack's ``local.conf``: VNCSERVER_LISTEN=0.0.0.0
.. code-block:: bash
VNCSERVER_LISTEN="0.0.0.0"
Environment final checkup Environment final checkup

View File

@@ -43,7 +43,7 @@ different version of the above, please document your configuration here!
Getting the latest code Getting the latest code
======================= =======================
Make a clone of the code from our ``Git repository``: Make a clone of the code from our `Git repository`:
.. code-block:: bash .. code-block:: bash
@@ -72,9 +72,9 @@ These dependencies can be installed from PyPi_ using the Python tool pip_.
.. _PyPi: https://pypi.org/ .. _PyPi: https://pypi.org/
.. _pip: https://pypi.org/project/pip .. _pip: https://pypi.org/project/pip
However, your system *may* need additional dependencies that ``pip`` (and by However, your system *may* need additional dependencies that `pip` (and by
extension, PyPi) cannot satisfy. These dependencies should be installed extension, PyPi) cannot satisfy. These dependencies should be installed
prior to using ``pip``, and the installation method may vary depending on prior to using `pip`, and the installation method may vary depending on
your platform. your platform.
* Ubuntu 16.04:: * Ubuntu 16.04::
@@ -141,7 +141,7 @@ forget to activate it:
$ workon watcher $ workon watcher
You should then be able to ``import watcher`` using Python without issue: You should then be able to `import watcher` using Python without issue:
.. code-block:: bash .. code-block:: bash

View File

@@ -56,6 +56,9 @@ Here is an example showing how you can write a plugin called ``NewStrategy``:
# filepath: thirdparty/new.py # filepath: thirdparty/new.py
# import path: thirdparty.new # import path: thirdparty.new
import abc import abc
import six
from watcher._i18n import _ from watcher._i18n import _
from watcher.decision_engine.strategy.strategies import base from watcher.decision_engine.strategy.strategies import base
@@ -300,6 +303,6 @@ Using that you can now query the values for that specific metric:
.. code-block:: py .. code-block:: py
avg_meter = self.datasource_backend.statistic_aggregation( avg_meter = self.datasource_backend.statistic_aggregation(
instance.uuid, 'instance_cpu_usage', self.periods['instance'], instance.uuid, 'cpu_util', self.periods['instance'],
self.granularity, self.granularity,
aggregation=self.aggregation_method['instance']) aggregation=self.aggregation_method['instance'])

View File

@@ -90,15 +90,15 @@ parameter will need to specify the type of http protocol and the use of
plain text http is strongly discouraged due to the transmission of the access plain text http is strongly discouraged due to the transmission of the access
token. Additionally the path to the proxy interface needs to be supplied as token. Additionally the path to the proxy interface needs to be supplied as
well in case Grafana is placed in a sub directory of the web server. An example well in case Grafana is placed in a sub directory of the web server. An example
would be: ``https://mygrafana.org/api/datasource/proxy/`` were would be: `https://mygrafana.org/api/datasource/proxy/` were
``/api/datasource/proxy`` is the default path without any subdirectories. `/api/datasource/proxy` is the default path without any subdirectories.
Likewise, this parameter can not be placed in the yaml. Likewise, this parameter can not be placed in the yaml.
To prevent many errors from occurring and potentially filing the logs files it To prevent many errors from occurring and potentially filing the logs files it
is advised to specify the desired datasource in the configuration as it would is advised to specify the desired datasource in the configuration as it would
prevent the datasource manager from having to iterate and try possible prevent the datasource manager from having to iterate and try possible
datasources with the launch of each audit. To do this specify datasources with the launch of each audit. To do this specify `datasources` in
``datasources`` in the ``[watcher_datasources]`` group. the `[watcher_datasources]` group.
The current configuration that is required to be placed in the traditional The current configuration that is required to be placed in the traditional
configuration file would look like the following: configuration file would look like the following:
@@ -120,7 +120,7 @@ traditional configuration file or in the yaml, however, it is not advised to
mix and match but in the case it does occur the yaml would override the mix and match but in the case it does occur the yaml would override the
settings from the traditional configuration file. All five of these parameters settings from the traditional configuration file. All five of these parameters
are dictionaries mapping specific metrics to a configuration parameter. For are dictionaries mapping specific metrics to a configuration parameter. For
instance the ``project_id_map`` will specify the specific project id in Grafana instance the `project_id_map` will specify the specific project id in Grafana
to be used. The parameters are named as follow: to be used. The parameters are named as follow:
* project_id_map * project_id_map
@@ -149,10 +149,10 @@ project_id
The project id's can only be determined by someone with the admin role in The project id's can only be determined by someone with the admin role in
Grafana as that role is required to open the list of projects. The list of Grafana as that role is required to open the list of projects. The list of
projects can be found on ``/datasources`` in the web interface but projects can be found on `/datasources` in the web interface but
unfortunately it does not immediately display the project id. To display unfortunately it does not immediately display the project id. To display
the id one can best hover the mouse over the projects and the url will show the the id one can best hover the mouse over the projects and the url will show the
project id's for example ``/datasources/edit/7563``. Alternatively the entire project id's for example `/datasources/edit/7563`. Alternatively the entire
list of projects can be retrieved using the `REST api`_. To easily make list of projects can be retrieved using the `REST api`_. To easily make
requests to the REST api a tool such as Postman can be used. requests to the REST api a tool such as Postman can be used.
@@ -239,24 +239,18 @@ conversion from bytes to megabytes.
SELECT value/1000000 FROM memory... SELECT value/1000000 FROM memory...
Queries will be formatted using the .format string method within Python. Queries will be formatted using the .format string method within Python. This
This format will currently have give attributes exposed to it labeled format will currently have give attributes exposed to it labeled `{0}` to
``{0}`` through ``{4}``. `{4}`. Every occurrence of these characters within the string will be replaced
Every occurrence of these characters within the string will be replaced
with the specific attribute. with the specific attribute.
{0} - {0} is the aggregate typically `mean`, `min`, `max` but `count` is also
is the aggregate typically ``mean``, ``min``, ``max`` but ``count`` supported.
is also supported. - {1} is the attribute as specified in the attribute parameter.
{1} - {2} is the period of time to aggregate data over in seconds.
is the attribute as specified in the attribute parameter. - {3} is the granularity or the interval between data points in seconds.
{2} - {4} is translator specific and in the case of InfluxDB it will be used for
is the period of time to aggregate data over in seconds. retention_periods.
{3}
is the granularity or the interval between data points in seconds.
{4}
is translator specific and in the case of InfluxDB it will be used for
retention_periods.
**InfluxDB** **InfluxDB**

View File

@@ -1,140 +0,0 @@
=====================
Prometheus datasource
=====================
Synopsis
--------
The Prometheus datasource allows Watcher to use a Prometheus server as the
source for collected metrics used by the Watcher decision engine. At minimum
deployers must configure the ``host`` and ``port`` at which the Prometheus
server is listening.
Requirements
-------------
It is required that Prometheus metrics contain a label to identify the hostname
of the exporter from which the metric was collected. This is used to match
against the Watcher cluster model ``ComputeNode.hostname``. The default for
this label is ``fqdn`` and in the prometheus scrape configs would look like:
.. code-block::
scrape_configs:
- job_name: node
static_configs:
- targets: ['10.1.2.3:9100']
labels:
fqdn: "testbox.controlplane.domain"
This default can be overridden when a deployer uses a different label to
identify the exporter host (for example ``hostname`` or ``host``, or any other
label, as long as it identifies the host).
Internally this label is used in creating a ``fqdn_instance_map``, mapping
the fqdn with the Prometheus instance label associated with each exporter.
The keys of the resulting fqdn_instance_map are expected to match the
``ComputeNode.hostname`` used in the Watcher decision engine cluster model.
An example ``fqdn_instance_map`` is the following:
.. code-block::
{
'ena.controlplane.domain': '10.1.2.1:9100',
'dio.controlplane.domain': '10.1.2.2:9100',
'tria.controlplane.domain': '10.1.2.3:9100'
}
For instance metrics, it is required that Prometheus contains a label
with the uuid of the OpenStack instance in each relevant metric. By default,
the datasource will look for the label ``resource``. The
``instance_uuid_label`` config option in watcher.conf allows deployers to
override this default to any other label name that stores the ``uuid``.
Limitations
-----------
The current implementation doesn't support the ``statistic_series`` function of
the Watcher ``class DataSourceBase``. It is expected that the
``statistic_aggregation`` function (which is implemented) is sufficient in
providing the **current** state of the managed resources in the cluster.
The ``statistic_aggregation`` function defaults to querying back 300 seconds,
starting from the present time (the time period is a function parameter and
can be set to a value as required). Implementing the ``statistic_series`` can
always be re-visited if the requisite interest and work cycles are volunteered
by the interested parties.
One further note about a limitation in the implemented
``statistic_aggregation`` function. This function is defined with a
``granularity`` parameter, to be used when querying whichever of the Watcher
``DataSourceBase`` metrics providers. In the case of Prometheus, we do not
fetch and then process individual metrics across the specified time period.
Instead we use the PromQL querying operators and functions, so that the
server itself will process the request across the specified parameters and
then return the result. So ``granularity`` parameter is redundant and remains
unused for the Prometheus implementation of ``statistic_aggregation``. The
granularity of the data fetched by Prometheus server is specified in
configuration as the server ``scrape_interval`` (current default 15 seconds).
Configuration
-------------
A deployer must set the ``datasources`` parameter to include ``prometheus``
under the watcher_datasources section of watcher.conf (or add ``prometheus`` in
datasources for a specific strategy if preferred eg. under the
``[watcher_strategies.workload_stabilization]`` section).
The watcher.conf configuration file is also used to set the parameter values
required by the Watcher Prometheus data source. The configuration can be
added under the ``[prometheus_client]`` section and the available options are
duplicated below from the code as they are self documenting:
.. code-block::
cfg.StrOpt('host',
help="The hostname or IP address for the prometheus server."),
cfg.StrOpt('port',
help="The port number used by the prometheus server."),
cfg.StrOpt('fqdn_label',
default="fqdn",
help="The label that Prometheus uses to store the fqdn of "
"exporters. Defaults to 'fqdn'."),
cfg.StrOpt('instance_uuid_label',
default="resource",
help="The label that Prometheus uses to store the uuid of "
"OpenStack instances. Defaults to 'resource'."),
cfg.StrOpt('username',
help="The basic_auth username to use to authenticate with the "
"Prometheus server."),
cfg.StrOpt('password',
secret=True,
help="The basic_auth password to use to authenticate with the "
"Prometheus server."),
cfg.StrOpt('cafile',
help="Path to the CA certificate for establishing a TLS "
"connection with the Prometheus server."),
cfg.StrOpt('certfile',
help="Path to the client certificate for establishing a TLS "
"connection with the Prometheus server."),
cfg.StrOpt('keyfile',
help="Path to the client key for establishing a TLS "
"connection with the Prometheus server."),
The ``host`` and ``port`` are **required** configuration options which have
no set default. These specify the hostname (or IP) and port for at which
the Prometheus server is listening. The ``fqdn_label`` allows deployers to
override the required metric label used to match Prometheus node exporters
against the Watcher ComputeNodes in the Watcher decision engine cluster data
model. The default is ``fqdn`` and deployers can specify any other value
(e.g. if they have an equivalent but different label such as ``host``).
So a sample watcher.conf configured to use the Prometheus server at
``10.2.3.4:9090`` would look like the following:
.. code-block::
[watcher_datasources]
datasources = prometheus
[prometheus_client]
host = 10.2.3.4
port = 9090
fqdn_label = fqdn

View File

@@ -9,7 +9,7 @@
... ...
connection = mysql+pymysql://watcher:WATCHER_DBPASS@controller/watcher?charset=utf8 connection = mysql+pymysql://watcher:WATCHER_DBPASS@controller/watcher?charset=utf8
* In the ``[DEFAULT]`` section, configure the transport url for RabbitMQ message broker. * In the `[DEFAULT]` section, configure the transport url for RabbitMQ message broker.
.. code-block:: ini .. code-block:: ini
@@ -20,7 +20,7 @@
Replace the RABBIT_PASS with the password you chose for OpenStack user in RabbitMQ. Replace the RABBIT_PASS with the password you chose for OpenStack user in RabbitMQ.
* In the ``[keystone_authtoken]`` section, configure Identity service access. * In the `[keystone_authtoken]` section, configure Identity service access.
.. code-block:: ini .. code-block:: ini
@@ -39,7 +39,7 @@
Replace WATCHER_PASS with the password you chose for the watcher user in the Identity service. Replace WATCHER_PASS with the password you chose for the watcher user in the Identity service.
* Watcher interacts with other OpenStack projects via project clients, in order to instantiate these * Watcher interacts with other OpenStack projects via project clients, in order to instantiate these
clients, Watcher requests new session from Identity service. In the ``[watcher_clients_auth]`` section, clients, Watcher requests new session from Identity service. In the `[watcher_clients_auth]` section,
configure the identity service access to interact with other OpenStack project clients. configure the identity service access to interact with other OpenStack project clients.
.. code-block:: ini .. code-block:: ini
@@ -56,7 +56,7 @@
Replace WATCHER_PASS with the password you chose for the watcher user in the Identity service. Replace WATCHER_PASS with the password you chose for the watcher user in the Identity service.
* In the ``[api]`` section, configure host option. * In the `[api]` section, configure host option.
.. code-block:: ini .. code-block:: ini
@@ -66,7 +66,7 @@
Replace controller with the IP address of the management network interface on your controller node, typically 10.0.0.11 for the first node in the example architecture. Replace controller with the IP address of the management network interface on your controller node, typically 10.0.0.11 for the first node in the example architecture.
* In the ``[oslo_messaging_notifications]`` section, configure the messaging driver. * In the `[oslo_messaging_notifications]` section, configure the messaging driver.
.. code-block:: ini .. code-block:: ini

View File

@@ -48,7 +48,7 @@
logging configuration to any other existing logging logging configuration to any other existing logging
options. Please see the Python logging module documentation options. Please see the Python logging module documentation
for details on logging configuration files. The log-config for details on logging configuration files. The log-config
name for this option is deprecated. name for this option is depcrecated.
**--log-format FORMAT** **--log-format FORMAT**
A logging.Formatter log message format string which may use any A logging.Formatter log message format string which may use any

View File

@@ -26,7 +26,8 @@ metric service name plugins comment
``compute_monitors`` option ``compute_monitors`` option
to ``cpu.virt_driver`` in to ``cpu.virt_driver`` in
the nova.conf. the nova.conf.
``cpu`` ceilometer_ none ``cpu_util`` ceilometer_ none cpu_util has been removed
since Stein.
============================ ============ ======= =========================== ============================ ============ ======= ===========================
.. _ceilometer: https://docs.openstack.org/ceilometer/latest/admin/telemetry-measurements.html#openstack-compute .. _ceilometer: https://docs.openstack.org/ceilometer/latest/admin/telemetry-measurements.html#openstack-compute

View File

@@ -89,9 +89,9 @@ step 2: Create audit to do optimization
.. code-block:: shell .. code-block:: shell
$ openstack optimize audittemplate create \ $ openstack optimize audittemplate create \
saving_energy_template1 saving_energy --strategy saving_energy at1 saving_energy --strategy saving_energy
$ openstack optimize audit create -a saving_energy_audit1 \ $ openstack optimize audit create -a at1 \
-p free_used_percent=20.0 -p free_used_percent=20.0
External Links External Links

View File

@@ -22,19 +22,14 @@ The *vm_workload_consolidation* strategy requires the following metrics:
============================ ============ ======= ========================= ============================ ============ ======= =========================
metric service name plugins comment metric service name plugins comment
============================ ============ ======= ========================= ============================ ============ ======= =========================
``cpu`` ceilometer_ none ``cpu_util`` ceilometer_ none cpu_util has been removed
since Stein.
``memory.resident`` ceilometer_ none ``memory.resident`` ceilometer_ none
``memory`` ceilometer_ none ``memory`` ceilometer_ none
``disk.root.size`` ceilometer_ none ``disk.root.size`` ceilometer_ none
``compute.node.cpu.percent`` ceilometer_ none (optional) need to set the
``compute_monitors`` option
to ``cpu.virt_driver`` in the
nova.conf.
``hardware.memory.used`` ceilometer_ SNMP_ (optional)
============================ ============ ======= ========================= ============================ ============ ======= =========================
.. _ceilometer: https://docs.openstack.org/ceilometer/latest/admin/telemetry-measurements.html#openstack-compute .. _ceilometer: https://docs.openstack.org/ceilometer/latest/admin/telemetry-measurements.html#openstack-compute
.. _SNMP: https://docs.openstack.org/ceilometer/latest/admin/telemetry-measurements.html#snmp-based-meters
Cluster data model Cluster data model
****************** ******************

View File

@@ -27,8 +27,9 @@ metric service name plugins comment
to ``cpu.virt_driver`` in the to ``cpu.virt_driver`` in the
nova.conf. nova.conf.
``hardware.memory.used`` ceilometer_ SNMP_ ``hardware.memory.used`` ceilometer_ SNMP_
``cpu`` ceilometer_ none ``cpu_util`` ceilometer_ none cpu_util has been removed
``instance_ram_usage`` ceilometer_ none since Stein.
``memory.resident`` ceilometer_ none
============================ ============ ======= ============================= ============================ ============ ======= =============================
.. _ceilometer: https://docs.openstack.org/ceilometer/latest/admin/telemetry-measurements.html#openstack-compute .. _ceilometer: https://docs.openstack.org/ceilometer/latest/admin/telemetry-measurements.html#openstack-compute
@@ -106,10 +107,10 @@ parameter type default Value description
period of all received ones. period of all received ones.
==================== ====== ===================== ============================= ==================== ====== ===================== =============================
.. |metrics| replace:: ["instance_cpu_usage", "instance_ram_usage"] .. |metrics| replace:: ["cpu_util", "memory.resident"]
.. |thresholds| replace:: {"instance_cpu_usage": 0.2, "instance_ram_usage": 0.2} .. |thresholds| replace:: {"cpu_util": 0.2, "memory.resident": 0.2}
.. |weights| replace:: {"instance_cpu_usage_weight": 1.0, "instance_ram_usage_weight": 1.0} .. |weights| replace:: {"cpu_util_weight": 1.0, "memory.resident_weight": 1.0}
.. |instance_metrics| replace:: {"instance_cpu_usage": "compute.node.cpu.percent", "instance_ram_usage": "hardware.memory.used"} .. |instance_metrics| replace:: {"cpu_util": "compute.node.cpu.percent", "memory.resident": "hardware.memory.used"}
.. |periods| replace:: {"instance": 720, "node": 600} .. |periods| replace:: {"instance": 720, "node": 600}
Efficacy Indicator Efficacy Indicator
@@ -135,8 +136,8 @@ How to use it ?
at1 workload_balancing --strategy workload_stabilization at1 workload_balancing --strategy workload_stabilization
$ openstack optimize audit create -a at1 \ $ openstack optimize audit create -a at1 \
-p thresholds='{"instance_ram_usage": 0.05}' \ -p thresholds='{"memory.resident": 0.05}' \
-p metrics='["instance_ram_usage"]' -p metrics='["memory.resident"]'
External Links External Links
-------------- --------------

View File

@@ -24,7 +24,8 @@ The *workload_balance* strategy requires the following metrics:
======================= ============ ======= ========================= ======================= ============ ======= =========================
metric service name plugins comment metric service name plugins comment
======================= ============ ======= ========================= ======================= ============ ======= =========================
``cpu`` ceilometer_ none ``cpu_util`` ceilometer_ none cpu_util has been removed
since Stein.
``memory.resident`` ceilometer_ none ``memory.resident`` ceilometer_ none
======================= ============ ======= ========================= ======================= ============ ======= =========================
@@ -64,16 +65,15 @@ Configuration
Strategy parameters are: Strategy parameters are:
============== ====== ==================== ==================================== ============== ====== ============= ====================================
parameter type default Value description parameter type default Value description
============== ====== ==================== ==================================== ============== ====== ============= ====================================
``metrics`` String 'instance_cpu_usage' Workload balance base on cpu or ram ``metrics`` String 'cpu_util' Workload balance base on cpu or ram
utilization. Choices: utilization. choice: ['cpu_util',
['instance_cpu_usage', 'memory.resident']
'instance_ram_usage'] ``threshold`` Number 25.0 Workload threshold for migration
``threshold`` Number 25.0 Workload threshold for migration ``period`` Number 300 Aggregate time period of ceilometer
``period`` Number 300 Aggregate time period of ceilometer ============== ====== ============= ====================================
============== ====== ==================== ====================================
Efficacy Indicator Efficacy Indicator
------------------ ------------------
@@ -95,7 +95,7 @@ How to use it ?
at1 workload_balancing --strategy workload_balance at1 workload_balancing --strategy workload_balance
$ openstack optimize audit create -a at1 -p threshold=26.0 \ $ openstack optimize audit create -a at1 -p threshold=26.0 \
-p period=310 -p metrics=instance_cpu_usage -p period=310 -p metrics=cpu_util
External Links External Links
-------------- --------------

View File

@@ -132,8 +132,8 @@ audit) that you want to use.
$ openstack optimize audit create -a <your_audit_template> $ openstack optimize audit create -a <your_audit_template>
If your_audit_template was created by --strategy <your_strategy>, and it If your_audit_template was created by --strategy <your_strategy>, and it
defines some parameters (command ``watcher strategy show`` to check parameters defines some parameters (command `watcher strategy show` to check parameters
format), your can append ``-p`` to input required parameters: format), your can append `-p` to input required parameters:
.. code:: bash .. code:: bash

150
lower-constraints.txt Normal file
View File

@@ -0,0 +1,150 @@
alabaster==0.7.10
alembic==0.9.8
amqp==2.2.2
appdirs==1.4.3
APScheduler==3.5.1
asn1crypto==0.24.0
automaton==1.14.0
beautifulsoup4==4.6.0
cachetools==2.0.1
certifi==2018.1.18
cffi==1.14.0
chardet==3.0.4
cliff==2.11.0
cmd2==0.8.1
contextlib2==0.5.5
coverage==4.5.1
croniter==0.3.20
cryptography==2.1.4
debtcollector==1.19.0
decorator==4.2.1
deprecation==2.0
doc8==0.8.0
docutils==0.14
dogpile.cache==0.6.5
dulwich==0.19.0
enum34==1.1.6
enum-compat==0.0.2
eventlet==0.20.0
extras==1.0.0
fasteners==0.14.1
fixtures==3.0.0
freezegun==0.3.10
futurist==1.8.0
gitdb2==2.0.3
GitPython==2.1.8
gnocchiclient==7.0.1
greenlet==0.4.15
idna==2.6
imagesize==1.0.0
iso8601==0.1.12
Jinja2==2.10
jmespath==0.9.3
jsonpatch==1.21
jsonpointer==2.0
jsonschema==3.2.0
keystoneauth1==3.4.0
keystonemiddleware==4.21.0
kombu==5.0.0
linecache2==1.0.0
logutils==0.3.5
lxml==4.5.1
Mako==1.0.7
MarkupSafe==1.1.1
mccabe==0.2.1
microversion_parse==0.2.1
monotonic==1.4
msgpack==0.5.6
munch==2.2.0
netaddr==0.7.19
netifaces==0.10.6
networkx==2.4
openstacksdk==0.12.0
os-api-ref===1.4.0
os-client-config==1.29.0
os-service-types==1.2.0
os-testr==1.0.0
osc-lib==1.10.0
os-resource-classes==0.4.0
oslo.cache==1.29.0
oslo.concurrency==3.26.0
oslo.config==5.2.0
oslo.context==2.21.0
oslo.db==4.44.0
oslo.i18n==3.20.0
oslo.log==3.37.0
oslo.messaging==8.1.2
oslo.middleware==3.35.0
oslo.policy==1.34.0
oslo.reports==1.27.0
oslo.serialization==2.25.0
oslo.service==1.30.0
oslo.upgradecheck==0.1.0
oslo.utils==3.36.0
oslo.versionedobjects==1.32.0
oslotest==3.3.0
packaging==17.1
Paste==2.0.3
PasteDeploy==1.5.2
pbr==3.1.1
pecan==1.3.2
pika==0.10.0
pika-pool==0.1.3
prettytable==0.7.2
psutil==5.4.3
pycadf==2.7.0
pycparser==2.18
Pygments==2.2.0
pyinotify==0.9.6
pyOpenSSL==17.5.0
pyparsing==2.2.0
pyperclip==1.6.0
python-ceilometerclient==2.9.0
python-cinderclient==3.5.0
python-dateutil==2.7.0
python-editor==1.0.3
python-glanceclient==2.9.1
python-ironicclient==2.5.0
python-keystoneclient==3.15.0
python-mimeparse==1.6.0
python-monascaclient==1.12.0
python-neutronclient==6.7.0
python-novaclient==14.1.0
python-openstackclient==3.14.0
python-subunit==1.2.0
pytz==2018.3
PyYAML==3.13
repoze.lru==0.7
requests==2.18.4
requestsexceptions==1.4.0
restructuredtext-lint==1.1.3
rfc3986==1.1.0
Routes==2.4.1
simplegeneric==0.8.1
simplejson==3.13.2
smmap2==2.0.3
snowballstemmer==1.2.1
SQLAlchemy==1.2.5
sqlalchemy-migrate==0.11.0
sqlparse==0.2.4
statsd==3.2.2
stestr==2.0.0
stevedore==1.28.0
taskflow==3.8.0
Tempita==0.5.2
tenacity==4.12.0
testresources==2.0.1
testscenarios==0.5.0
testtools==2.3.0
traceback2==1.4.0
tzlocal==1.5.1
ujson==1.35
unittest2==1.1.0
urllib3==1.22
vine==1.1.4
waitress==1.1.0
warlock==1.3.0
WebOb==1.8.5
WebTest==2.0.29
wrapt==1.10.11
WSME==0.9.2

View File

@@ -1,9 +0,0 @@
---
- hosts: all
tasks:
- name: Generate prometheus.yml config file
delegate_to: controller
template:
src: "templates/prometheus.yml.j2"
dest: "/home/zuul/prometheus.yml"
mode: "0644"

View File

@@ -1,13 +0,0 @@
global:
scrape_interval: 10s
scrape_configs:
- job_name: "node"
static_configs:
- targets: ["localhost:3000"]
{% if 'compute' in groups %}
{% for host in groups['compute'] %}
- targets: ["{{ hostvars[host]['ansible_fqdn'] }}:9100"]
labels:
fqdn: "{{ hostvars[host]['ansible_fqdn'] }}"
{% endfor %}
{% endif %}

View File

@@ -1,8 +1,7 @@
Rally job Rally job
========= =========
We provide, with Watcher, a Rally plugin you can use to benchmark We provide, with Watcher, a Rally plugin you can use to benchmark the optimization service.
the optimization service.
To launch this task with configured Rally you just need to run: To launch this task with configured Rally you just need to run:

View File

@@ -1,33 +0,0 @@
---
prelude: |
The ``Openstack 2025.1`` (``Watcher 14.0.0``) includes several new features,
deprecations, and removals. After a period of inactivity, the Watcher
project moved to the Distributed leadership model in ``2025.1`` with
several new contributors working to modernize the code base.
Activity this cycle was mainly focused on paying down technical debt
related to supporting newer testing runtimes. With this release,
``ubuntu 24.04`` is now officially tested and supported.
``Ubuntu 24.04`` brings a new default Python runtime ``3.12`` and with it
improvements to eventlet and SQLAlchemy 2.0 compatibility where required.
``2025.1`` is the last release to officially support and test with ``Ubuntu 22.04``.
``2025.1`` is the second official skip-level upgrade release supporting
upgrades from either ``2024.1`` or ``2024.2``
Another area of focus in this cycle was the data sources supported by Watcher.
The long obsolete `Ceilometer` API data source has been removed, and the untested
`Monasca` data source has been deprecated and a new `Prometheus` data source
has been added.
https://specs.openstack.org/openstack/watcher-specs/specs/2025.1/approved/prometheus-datasource.html
fixes:
- https://bugs.launchpad.net/watcher/+bug/2086710 watcher compatibility between
eventlet, apscheduler, and python 3.12
- https://bugs.launchpad.net/watcher/+bug/2067815 refactoring of the SQLAlchemy
database layer to improve compatibility with eventlet on newer Pythons
- A number of linting issues were addressed with the introduction
of pre-commit. The issues include but are not limited to, spelling and grammar
fixes across all documentation and code, numerous sphinx documentation build warnings
, and incorrect file permission such as files having the execute bit set when not required.
While none of these changes should affect the runtime behavior of Watcher, they
generally improve the maintainability and quality of the codebase.

View File

@@ -1,6 +0,0 @@
---
features:
- |
Support for instance metrics has been added to the prometheus data source.
The included metrics are `instance_cpu_usage`, `instance_ram_usage`,
`instance_ram_allocated` and `instance_root_disk_size`.

View File

@@ -4,4 +4,4 @@ features:
will standardize interactions with scoring engines will standardize interactions with scoring engines
through the common API. It is possible to use the through the common API. It is possible to use the
scoring engine by different Strategies, which scoring engine by different Strategies, which
improve the code and data model reuse. improve the code and data model re-use.

View File

@@ -5,5 +5,5 @@ features:
failure. The amount of failures allowed before giving up and the time before failure. The amount of failures allowed before giving up and the time before
reattempting are configurable. The `api_call_retries` and reattempting are configurable. The `api_call_retries` and
`api_query_timeout` parameters in the `[collector]` group can be used to `api_query_timeout` parameters in the `[collector]` group can be used to
adjust these parameters. 10 retries with a 1 second time in between adjust these paremeters. 10 retries with a 1 second time in between
reattempts is the default. reattempts is the default.

View File

@@ -3,6 +3,6 @@ features:
Watcher starts to support API microversions since Stein cycle. From now Watcher starts to support API microversions since Stein cycle. From now
onwards all API changes should be made with saving backward compatibility. onwards all API changes should be made with saving backward compatibility.
To specify API version operator should use OpenStack-API-Version To specify API version operator should use OpenStack-API-Version
HTTP header. If operator wants to know the minimum and maximum supported HTTP header. If operator wants to know the mininum and maximum supported
versions by API, he/she can access /v1 resource and Watcher API will versions by API, he/she can access /v1 resource and Watcher API will
return appropriate headers in response. return appropriate headers in response.

View File

@@ -1,20 +0,0 @@
---
upgrade:
- |
The default value of ``[oslo_policy] policy_file`` config option has
been changed from ``policy.json`` to ``policy.yaml``.
Operators who are utilizing customized or previously generated
static policy JSON files (which are not needed by default), should
generate new policy files or convert them in YAML format. Use the
`oslopolicy-convert-json-to-yaml
<https://docs.openstack.org/oslo.policy/latest/cli/oslopolicy-convert-json-to-yaml.html>`_
tool to convert a JSON to YAML formatted policy file in
backward compatible way.
deprecations:
- |
Use of JSON policy files was deprecated by the ``oslo.policy`` library
during the Victoria development cycle. As a result, this deprecation is
being noted in the Wallaby cycle with an anticipated future removal of support
by ``oslo.policy``. As such operators will need to convert to YAML policy
files. Please see the upgrade notes for details on migration of any
custom policy files.

View File

@@ -1,5 +0,0 @@
---
deprecations:
- |
Monasca Data Source is deprecated and will be removed in the future, due
to inactivity of Monasca project.

View File

@@ -1,6 +0,0 @@
---
upgrade:
- |
Python 3.8 support has been dropped. Last release of watcher
supporting python 3.8 is 13.0.0.
The minimum version of Python now supported is Python 3.9.

View File

@@ -7,7 +7,7 @@ prelude: >
features: features:
- | - |
A new threadpool for the decision engine that contributors can use to A new threadpool for the decision engine that contributors can use to
improve the performance of many operations, primarily I/O bound ones. improve the performance of many operations, primarily I/O bound onces.
The amount of workers used by the decision engine threadpool can be The amount of workers used by the decision engine threadpool can be
configured to scale according to the available infrastructure using configured to scale according to the available infrastructure using
the `watcher_decision_engine.max_general_workers` config option. the `watcher_decision_engine.max_general_workers` config option.

View File

@@ -13,7 +13,7 @@ features:
* disk_gb_reserved: The amount of disk a node has reserved for its own use. * disk_gb_reserved: The amount of disk a node has reserved for its own use.
* disk_ratio: Disk allocation ratio. * disk_ratio: Disk allocation ratio.
We also add some new properties: We also add some new propeties:
* vcpu_capacity: The amount of vcpu, take allocation ratio into account, * vcpu_capacity: The amount of vcpu, take allocation ratio into account,
but do not include reserved. but do not include reserved.

View File

@@ -1,8 +0,0 @@
---
features:
- |
A new Prometheus data source is added. This allows the watcher decision
engine to collect metrics from Prometheus server. For more information
about the Prometheus data source, including limitations and configuration
options see
https://docs.openstack.org/watcher/latest/datasources/prometheus.html

View File

@@ -1,6 +0,0 @@
---
upgrade:
- |
Ceilometer datasource has been completely removed. The datasource requires
ceilometer API which was already removed from Ceilometer. Use the other
datasources such as Gnocchi.

View File

@@ -1,4 +1,4 @@
--- ---
features: features:
- Check the creation time of the action plan, - Check the creation time of the action plan,
and set its state to SUPERSEDED if it has expired. and set its state to SUPERSEDED if it has expired.

View File

@@ -4,5 +4,5 @@ features:
Whenever a Watcher object is created, updated or deleted, a versioned Whenever a Watcher object is created, updated or deleted, a versioned
notification will, if it's relevant, be automatically sent to notify in order notification will, if it's relevant, be automatically sent to notify in order
to allow an event-driven style of architecture within Watcher. Moreover, it to allow an event-driven style of architecture within Watcher. Moreover, it
will also give other services and/or 3rd party software (e.g. monitoring will also give other services and/or 3rd party softwares (e.g. monitoring
solutions or rules engines) the ability to react to such events. solutions or rules engines) the ability to react to such events.

View File

@@ -1,3 +1,3 @@
--- ---
features: features:
- Add a service supervisor to watch Watcher daemons. - Add a service supervisor to watch Watcher deamons.

View File

@@ -1,6 +0,0 @@
===========================
2023.1 Series Release Notes
===========================
.. release-notes::
:branch: unmaintained/2023.1

View File

@@ -1,6 +0,0 @@
===========================
2023.2 Series Release Notes
===========================
.. release-notes::
:branch: stable/2023.2

View File

@@ -1,6 +0,0 @@
===========================
2024.1 Series Release Notes
===========================
.. release-notes::
:branch: stable/2024.1

View File

@@ -1,6 +0,0 @@
===========================
2024.2 Series Release Notes
===========================
.. release-notes::
:branch: stable/2024.2

View File

@@ -28,12 +28,12 @@ import sys
# If extensions (or modules to document with autodoc) are in another directory, # If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the # add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here. # documentation root, use os.path.abspath to make it absolute, like shown here.
# sys.path.insert(0, os.path.abspath('.')) #sys.path.insert(0, os.path.abspath('.'))
# -- General configuration ---------------------------------------------------- # -- General configuration ----------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here. # If your documentation needs a minimal Sphinx version, state it here.
# needs_sphinx = '1.0' #needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be # Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
@@ -47,13 +47,13 @@ templates_path = ['_templates']
source_suffix = '.rst' source_suffix = '.rst'
# The encoding of source files. # The encoding of source files.
# source_encoding = 'utf-8-sig' #source_encoding = 'utf-8-sig'
# The master toctree document. # The master toctree document.
master_doc = 'index' master_doc = 'index'
# General information about the project. # General information about the project.
copyright = '2016, Watcher developers' copyright = u'2016, Watcher developers'
# Release notes are version independent # Release notes are version independent
# The short X.Y version. # The short X.Y version.
@@ -63,37 +63,37 @@ release = ''
# The language for content autogenerated by Sphinx. Refer to documentation # The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages. # for a list of supported languages.
# language = None #language = None
# There are two options for replacing |today|: either, you set today to some # There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used: # non-false value, then it is used:
# today = '' #today = ''
# Else, today_fmt is used as the format for a strftime call. # Else, today_fmt is used as the format for a strftime call.
# today_fmt = '%B %d, %Y' #today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and # List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files. # directories to ignore when looking for source files.
exclude_patterns = ['_build'] exclude_patterns = ['_build']
# The reST default role (used for this markup: `text`) to use for all documents # The reST default role (used for this markup: `text`) to use for all documents
# default_role = None #default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text. # If true, '()' will be appended to :func: etc. cross-reference text.
# add_function_parentheses = True #add_function_parentheses = True
# If true, the current module name will be prepended to all description # If true, the current module name will be prepended to all description
# unit titles (such as .. function::). # unit titles (such as .. function::).
# add_module_names = True #add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the # If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default. # output. They are ignored by default.
# show_authors = False #show_authors = False
# The name of the Pygments (syntax highlighting) style to use. # The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'native' pygments_style = 'native'
# A list of ignored prefixes for module index sorting. # A list of ignored prefixes for module index sorting.
# modindex_common_prefix = [] #modindex_common_prefix = []
# openstackdocstheme options # openstackdocstheme options
openstackdocs_repo_name = 'openstack/watcher' openstackdocs_repo_name = 'openstack/watcher'
@@ -109,26 +109,26 @@ html_theme = 'openstackdocs'
# Theme options are theme-specific and customize the look and feel of a theme # Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the # further. For a list of options available for each theme, see the
# documentation. # documentation.
# html_theme_options = {} #html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory. # Add any paths that contain custom themes here, relative to this directory.
# html_theme_path = [] #html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to # The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation". # "<project> v<release> documentation".
# html_title = None #html_title = None
# A shorter title for the navigation bar. Default is the same as html_title. # A shorter title for the navigation bar. Default is the same as html_title.
# html_short_title = None #html_short_title = None
# The name of an image file (relative to this directory) to place at the top # The name of an image file (relative to this directory) to place at the top
# of the sidebar. # of the sidebar.
# html_logo = None #html_logo = None
# The name of an image file (within the static path) to use as favicon of the # The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large. # pixels large.
# html_favicon = None #html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here, # Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files, # relative to this directory. They are copied after the builtin static files,
@@ -137,44 +137,44 @@ html_static_path = ['_static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format. # using the given strftime format.
# html_last_updated_fmt = '%b %d, %Y' #html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to # If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities. # typographically correct entities.
# html_use_smartypants = True #html_use_smartypants = True
# Custom sidebar templates, maps document names to template names. # Custom sidebar templates, maps document names to template names.
# html_sidebars = {} #html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to # Additional templates that should be rendered to pages, maps page names to
# template names. # template names.
# html_additional_pages = {} #html_additional_pages = {}
# If false, no module index is generated. # If false, no module index is generated.
# html_domain_indices = True #html_domain_indices = True
# If false, no index is generated. # If false, no index is generated.
# html_use_index = True #html_use_index = True
# If true, the index is split into individual pages for each letter. # If true, the index is split into individual pages for each letter.
# html_split_index = False #html_split_index = False
# If true, links to the reST sources are added to the pages. # If true, links to the reST sources are added to the pages.
# html_show_sourcelink = True #html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. # If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
# html_show_sphinx = True #html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
# html_show_copyright = True #html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will # If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the # contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served. # base URL from which the finished HTML is served.
# html_use_opensearch = '' #html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml"). # This is the file name suffix for HTML files (e.g. ".xhtml").
# html_file_suffix = None #html_file_suffix = None
# Output file base name for HTML help builder. # Output file base name for HTML help builder.
htmlhelp_basename = 'watcherdoc' htmlhelp_basename = 'watcherdoc'
@@ -183,42 +183,42 @@ htmlhelp_basename = 'watcherdoc'
# -- Options for LaTeX output ------------------------------------------------- # -- Options for LaTeX output -------------------------------------------------
latex_elements = { latex_elements = {
# The paper size ('letterpaper' or 'a4paper'). # The paper size ('letterpaper' or 'a4paper').
# 'papersize': 'letterpaper', #'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt'). # The font size ('10pt', '11pt' or '12pt').
# 'pointsize': '10pt', #'pointsize': '10pt',
# Additional stuff for the LaTeX preamble. # Additional stuff for the LaTeX preamble.
# 'preamble': '', #'preamble': '',
} }
# Grouping the document tree into LaTeX files. List of tuples # Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]) # (source start file, target name, title, author, documentclass [howto/manual])
latex_documents = [ latex_documents = [
('index', 'watcher.tex', 'Watcher Documentation', ('index', 'watcher.tex', u'Watcher Documentation',
'Watcher developers', 'manual'), u'Watcher developers', 'manual'),
] ]
# The name of an image file (relative to this directory) to place at the top of # The name of an image file (relative to this directory) to place at the top of
# the title page. # the title page.
# latex_logo = None #latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts, # For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters. # not chapters.
# latex_use_parts = False #latex_use_parts = False
# If true, show page references after internal links. # If true, show page references after internal links.
# latex_show_pagerefs = False #latex_show_pagerefs = False
# If true, show URL addresses after external links. # If true, show URL addresses after external links.
# latex_show_urls = False #latex_show_urls = False
# Documents to append as an appendix to all manuals. # Documents to append as an appendix to all manuals.
# latex_appendices = [] #latex_appendices = []
# If false, no module index is generated. # If false, no module index is generated.
# latex_domain_indices = True #latex_domain_indices = True
# -- Options for manual page output ------------------------------------------- # -- Options for manual page output -------------------------------------------
@@ -226,12 +226,12 @@ latex_documents = [
# One entry per manual page. List of tuples # One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section). # (source start file, name, description, authors, manual section).
man_pages = [ man_pages = [
('index', 'watcher', 'Watcher Documentation', ('index', 'watcher', u'Watcher Documentation',
['Watcher developers'], 1) [u'Watcher developers'], 1)
] ]
# If true, show URL addresses after external links. # If true, show URL addresses after external links.
# man_show_urls = False #man_show_urls = False
# -- Options for Texinfo output ----------------------------------------------- # -- Options for Texinfo output -----------------------------------------------
@@ -240,19 +240,19 @@ man_pages = [
# (source start file, target name, title, author, # (source start file, target name, title, author,
# dir menu entry, description, category) # dir menu entry, description, category)
texinfo_documents = [ texinfo_documents = [
('index', 'watcher', 'Watcher Documentation', ('index', 'watcher', u'Watcher Documentation',
'Watcher developers', 'watcher', 'One line description of project.', u'Watcher developers', 'watcher', 'One line description of project.',
'Miscellaneous'), 'Miscellaneous'),
] ]
# Documents to append as an appendix to all manuals. # Documents to append as an appendix to all manuals.
# texinfo_appendices = [] #texinfo_appendices = []
# If false, no module index is generated. # If false, no module index is generated.
# texinfo_domain_indices = True #texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'. # How to display URL addresses: 'footnote', 'no', or 'inline'.
# texinfo_show_urls = 'footnote' #texinfo_show_urls = 'footnote'
# -- Options for Internationalization output ------------------------------ # -- Options for Internationalization output ------------------------------
locale_dirs = ['locale/'] locale_dirs = ['locale/']

View File

@@ -21,15 +21,6 @@ Contents:
:maxdepth: 1 :maxdepth: 1
unreleased unreleased
2024.2
2024.1
2023.2
2023.1
zed
yoga
xena
wallaby
victoria
ussuri ussuri
train train
stein stein

View File

@@ -1,18 +1,14 @@
# Andi Chandler <andi@gowling.com>, 2017. #zanata # Andi Chandler <andi@gowling.com>, 2017. #zanata
# Andi Chandler <andi@gowling.com>, 2018. #zanata # Andi Chandler <andi@gowling.com>, 2018. #zanata
# Andi Chandler <andi@gowling.com>, 2020. #zanata
# Andi Chandler <andi@gowling.com>, 2022. #zanata
# Andi Chandler <andi@gowling.com>, 2023. #zanata
# Andi Chandler <andi@gowling.com>, 2024. #zanata
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: python-watcher\n" "Project-Id-Version: python-watcher\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-01-10 00:32+0000\n" "POT-Creation-Date: 2018-11-08 01:22+0000\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"PO-Revision-Date: 2024-04-18 12:21+0000\n" "PO-Revision-Date: 2018-11-07 06:15+0000\n"
"Last-Translator: Andi Chandler <andi@gowling.com>\n" "Last-Translator: Andi Chandler <andi@gowling.com>\n"
"Language-Team: English (United Kingdom)\n" "Language-Team: English (United Kingdom)\n"
"Language: en_GB\n" "Language: en_GB\n"
@@ -58,76 +54,6 @@ msgstr "1.7.0"
msgid "1.9.0" msgid "1.9.0"
msgstr "1.9.0" msgstr "1.9.0"
msgid "2.0.0"
msgstr "2.0.0"
msgid "2023.1 Series Release Notes"
msgstr "2023.1 Series Release Notes"
msgid "2023.2 Series Release Notes"
msgstr "2023.2 Series Release Notes"
msgid "3.0.0"
msgstr "3.0.0"
msgid "3.0.0.0rc1"
msgstr "3.0.0.0rc1"
msgid "4.0.0"
msgstr "4.0.0"
msgid "4.0.0.0rc1"
msgstr "4.0.0.0rc1"
msgid "6.0.0"
msgstr "6.0.0"
msgid "A ``watcher-status upgrade check`` has been added for this."
msgstr "A ``watcher-status upgrade check`` has been added for this."
msgid ""
"A new threadpool for the decision engine that contributors can use to "
"improve the performance of many operations, primarily I/O bound onces. The "
"amount of workers used by the decision engine threadpool can be configured "
"to scale according to the available infrastructure using the "
"`watcher_decision_engine.max_general_workers` config option. Documentation "
"for contributors to effectively use this threadpool is available online: "
"https://docs.openstack.org/watcher/latest/contributor/concurrency.html"
msgstr ""
"A new threadpool for the decision engine that contributors can use to "
"improve the performance of many operations, primarily I/O bound onces. The "
"amount of workers used by the decision engine threadpool can be configured "
"to scale according to the available infrastructure using the "
"`watcher_decision_engine.max_general_workers` config option. Documentation "
"for contributors to effectively use this threadpool is available online: "
"https://docs.openstack.org/watcher/latest/contributor/concurrency.html"
msgid ""
"API calls while building the Compute data model will be retried upon "
"failure. The amount of failures allowed before giving up and the time before "
"reattempting are configurable. The `api_call_retries` and "
"`api_query_timeout` parameters in the `[collector]` group can be used to "
"adjust these paremeters. 10 retries with a 1 second time in between "
"reattempts is the default."
msgstr ""
"API calls while building the Compute data model will be retried upon "
"failure. The amount of failures allowed before giving up and the time before "
"reattempting are configurable. The `api_call_retries` and "
"`api_query_timeout` parameters in the `[collector]` group can be used to "
"adjust these parameters. 10 retries with a 1 second time in between "
"reattempts is the default."
msgid ""
"Add a new webhook API and a new audit type EVENT, the microversion is 1.4. "
"Now Watcher user can create audit with EVENT type and the audit will be "
"triggered by webhook API. The user guide is available online: https://docs."
"openstack.org/watcher/latest/user/event_type_audit.html"
msgstr ""
"Add a new webhook API and a new audit type EVENT, the microversion is 1.4. "
"Now Watcher user can create audit with EVENT type and the audit will be "
"triggered by webhook API. The user guide is available online: https://docs."
"openstack.org/watcher/latest/user/event_type_audit.html"
msgid "Add a service supervisor to watch Watcher deamons." msgid "Add a service supervisor to watch Watcher deamons."
msgstr "Add a service supervisor to watch Watcher daemons." msgstr "Add a service supervisor to watch Watcher daemons."
@@ -141,24 +67,6 @@ msgstr ""
"Add description property for dynamic action. Admin can see detail " "Add description property for dynamic action. Admin can see detail "
"information of any specify action." "information of any specify action."
msgid ""
"Add force field to Audit. User can set --force to enable the new option when "
"launching audit. If force is True, audit will be executed despite of ongoing "
"actionplan. The new audit may create a wrong actionplan if they use the same "
"data model."
msgstr ""
"Add force field to Audit. User can set --force to enable the new option when "
"launching audit. If force is True, audit will be executed despite of ongoing "
"actionplan. The new audit may create a wrong actionplan if they use the same "
"data model."
msgid ""
"Add keystone_client Group for user to configure 'interface' and "
"'region_name' by watcher.conf. The default value of 'interface' is 'admin'."
msgstr ""
"Add keystone_client Group for user to configure 'interface' and "
"'region_name' by watcher.conf. The default value of 'interface' is 'admin'."
msgid "Add notifications related to Action object." msgid "Add notifications related to Action object."
msgstr "Add notifications related to Action object." msgstr "Add notifications related to Action object."
@@ -171,25 +79,6 @@ msgstr "Add notifications related to Audit object."
msgid "Add notifications related to Service object." msgid "Add notifications related to Service object."
msgstr "Add notifications related to Service object." msgstr "Add notifications related to Service object."
msgid ""
"Add show data model api for Watcher. New in version 1.3. User can use "
"'openstack optimize datamodel list' command to view the current data model "
"information in memory. User can also add '--audit <Audit_UUID>' to view "
"specific data model in memory filted by the scope in audit. User can also "
"add '--detail' to view detailed information about current data model. User "
"can also add '--type <type>' to specify the type of data model. Default type "
"is 'compute'. In the future, type 'storage' and 'baremetal' will be "
"supported."
msgstr ""
"Add show data model API for Watcher. New in version 1.3. User can use "
"'openstack optimize datamodel list' command to view the current data model "
"information in memory. User can also add '--audit <Audit_UUID>' to view "
"specific data model in memory filtered by the scope in audit. User can also "
"add '--detail' to view detailed information about current data model. User "
"can also add '--type <type>' to specify the type of data model. Default type "
"is 'compute'. In the future, type 'storage' and 'baremetal' will be "
"supported."
msgid "" msgid ""
"Add start_time and end_time fields in audits table. User can set the start " "Add start_time and end_time fields in audits table. User can set the start "
"time and/or end time when creating CONTINUOUS audit." "time and/or end time when creating CONTINUOUS audit."
@@ -204,33 +93,9 @@ msgstr ""
"Add superseded state for an action plan if the cluster data model has " "Add superseded state for an action plan if the cluster data model has "
"changed after it has been created." "changed after it has been created."
msgid ""
"Added Placement API helper to Watcher. Now Watcher can get information about "
"resource providers, it can be used for the data model and strategies. Config "
"group placement_client with options 'api_version', 'interface' and "
"'region_name' is also added. The default values for 'api_version' and "
"'interface' are 1.29 and 'public', respectively."
msgstr ""
"Added Placement API helper to Watcher. Now Watcher can get information about "
"resource providers, it can be used for the data model and strategies. Config "
"group placement_client with options 'api_version', 'interface' and "
"'region_name' is also added. The default values for 'api_version' and "
"'interface' are 1.29 and 'public', respectively."
msgid "Added SUSPENDED audit state" msgid "Added SUSPENDED audit state"
msgstr "Added SUSPENDED audit state" msgstr "Added SUSPENDED audit state"
msgid ""
"Added a generic scoring engine module, which will standardize interactions "
"with scoring engines through the common API. It is possible to use the "
"scoring engine by different Strategies, which improve the code and data "
"model re-use."
msgstr ""
"Added a generic scoring engine module, which will standardize interactions "
"with scoring engines through the common API. It is possible to use the "
"scoring engine by different Strategies, which improve the code and data "
"model re-use."
msgid "" msgid ""
"Added a generic scoring engine module, which will standarize interactions " "Added a generic scoring engine module, which will standarize interactions "
"with scoring engines through the common API. It is possible to use the " "with scoring engines through the common API. It is possible to use the "
@@ -242,31 +107,6 @@ msgstr ""
"scoring engine by different Strategies, which improve the code and data " "scoring engine by different Strategies, which improve the code and data "
"model re-use." "model re-use."
msgid ""
"Added a new config option 'action_execution_rule' which is a dict type. Its "
"key field is strategy name and the value is 'ALWAYS' or 'ANY'. 'ALWAYS' "
"means the callback function returns True as usual. 'ANY' means the return "
"depends on the result of previous action execution. The callback returns "
"True if previous action gets failed, and the engine continues to run the "
"next action. If previous action executes success, the callback returns False "
"then the next action will be ignored. For strategies that aren't in "
"'action_execution_rule', the callback always returns True. Please add the "
"next section in the watcher.conf file if your strategy needs this feature. "
"[watcher_workflow_engines.taskflow] action_execution_rule = {'your strategy "
"name': 'ANY'}"
msgstr ""
"Added a new config option 'action_execution_rule' which is a dict type. Its "
"key field is strategy name and the value is 'ALWAYS' or 'ANY'. 'ALWAYS' "
"means the callback function returns True as usual. 'ANY' means the return "
"depends on the result of previous action execution. The callback returns "
"True if previous action gets failed, and the engine continues to run the "
"next action. If previous action executes success, the callback returns False "
"then the next action will be ignored. For strategies that aren't in "
"'action_execution_rule', the callback always returns True. Please add the "
"next section in the watcher.conf file if your strategy needs this feature. "
"[watcher_workflow_engines.taskflow] action_execution_rule = {'your strategy "
"name': 'ANY'}"
msgid "" msgid ""
"Added a new strategy based on the airflow of servers. This strategy makes " "Added a new strategy based on the airflow of servers. This strategy makes "
"decisions to migrate VMs to make the airflow uniform." "decisions to migrate VMs to make the airflow uniform."
@@ -350,13 +190,6 @@ msgstr ""
"Added a way to create periodic audit to be able to continuously optimise the " "Added a way to create periodic audit to be able to continuously optimise the "
"cloud infrastructure." "cloud infrastructure."
msgid ""
"Added a way to return the of available goals depending on which strategies "
"have been deployed on the node where the decision engine is running."
msgstr ""
"Added a way to return the of available goals depending on which strategies "
"have been deployed on the node where the decision engine is running."
msgid "" msgid ""
"Added a way to return the of available goals depending on which strategies " "Added a way to return the of available goals depending on which strategies "
"have been deployed on the node where the decison engine is running." "have been deployed on the node where the decison engine is running."
@@ -415,15 +248,6 @@ msgstr ""
"The strategy migrates many instances and volumes efficiently with minimum " "The strategy migrates many instances and volumes efficiently with minimum "
"downtime automatically." "downtime automatically."
msgid ""
"Added strategy \"node resource consolidation\". This strategy is used to "
"centralize VMs to as few nodes as possible by VM migration. User can set an "
"input parameter to decide how to select the destination node."
msgstr ""
"Added strategy \"node resource consolidation\". This strategy is used to "
"centralize VMs to as few nodes as possible by VM migration. User can set an "
"input parameter to decide how to select the destination node."
msgid "" msgid ""
"Added strategy to identify and migrate a Noisy Neighbor - a low priority VM " "Added strategy to identify and migrate a Noisy Neighbor - a low priority VM "
"that negatively affects peformance of a high priority VM by over utilizing " "that negatively affects peformance of a high priority VM by over utilizing "
@@ -433,15 +257,6 @@ msgstr ""
"that negatively affects performance of a high priority VM by over utilising " "that negatively affects performance of a high priority VM by over utilising "
"Last Level Cache." "Last Level Cache."
msgid ""
"Added strategy to identify and migrate a Noisy Neighbor - a low priority VM "
"that negatively affects performance of a high priority VM by over utilizing "
"Last Level Cache."
msgstr ""
"Added strategy to identify and migrate a Noisy Neighbour - a low-priority VM "
"that negatively affects the performance of a high-priority VM by over "
"utilising Last Level Cache."
msgid "" msgid ""
"Added the functionality to filter out instances which have metadata field " "Added the functionality to filter out instances which have metadata field "
"'optimize' set to False. For now, this is only available for the " "'optimize' set to False. For now, this is only available for the "
@@ -469,19 +284,6 @@ msgstr ""
msgid "Adds baremetal data model in Watcher" msgid "Adds baremetal data model in Watcher"
msgstr "Adds baremetal data model in Watcher" msgstr "Adds baremetal data model in Watcher"
msgid ""
"All datasources can now be configured to retry retrieving a metric upon "
"encountering an error. Between each attempt will be a set amount of time "
"which can be adjusted from the configuration. These configuration options "
"can be found in the `[watcher_datasources]` group and are named "
"`query_max_retries` and `query_timeout`."
msgstr ""
"All datasources can now be configured to retry retrieving a metric upon "
"encountering an error. Between each attempt will be a set amount of time "
"which can be adjusted from the configuration. These configuration options "
"can be found in the `[watcher_datasources]` group and are named "
"`query_max_retries` and `query_timeout`."
msgid "" msgid ""
"Allow decision engine to pass strategy parameters, like optimization " "Allow decision engine to pass strategy parameters, like optimization "
"threshold, to selected strategy, also strategy to provide parameters info to " "threshold, to selected strategy, also strategy to provide parameters info to "
@@ -491,34 +293,6 @@ msgstr ""
"threshold, to selected strategy, also strategy to provide parameters info to " "threshold, to selected strategy, also strategy to provide parameters info to "
"end user." "end user."
msgid ""
"Allow using file to override metric map. Override the metric map of each "
"datasource as soon as it is created by the manager. This override comes from "
"a file whose path is provided by a setting in config file. The setting is "
"`watcher_decision_engine/metric_map_path`. The file contains a map per "
"datasource whose keys are the metric names as recognized by watcher and the "
"value is the real name of the metric in the datasource. This setting "
"defaults to `/etc/watcher/metric_map.yaml`, and presence of this file is "
"optional."
msgstr ""
"Allow using file to override metric map. Override the metric map of each "
"datasource as soon as it is created by the manager. This override comes from "
"a file whose path is provided by a setting in config file. The setting is "
"`watcher_decision_engine/metric_map_path`. The file contains a map per "
"datasource whose keys are the metric names as recognized by watcher and the "
"value is the real name of the metric in the datasource. This setting "
"defaults to `/etc/watcher/metric_map.yaml`, and presence of this file is "
"optional."
msgid ""
"An Watcher API WSGI application script ``watcher-api-wsgi`` is now "
"available. It is auto-generated by ``pbr`` and allows to run the API service "
"using WSGI server (for example Nginx and uWSGI)."
msgstr ""
"An Watcher API WSGI application script ``watcher-api-wsgi`` is now "
"available. It is auto-generated by ``pbr`` and allows to run the API service "
"using WSGI server (for example Nginx and uWSGI)."
msgid "" msgid ""
"Audits have 'name' field now, that is more friendly to end users. Audit's " "Audits have 'name' field now, that is more friendly to end users. Audit's "
"name can't exceed 63 characters." "name can't exceed 63 characters."
@@ -526,35 +300,12 @@ msgstr ""
"Audits have 'name' field now, that is more friendly to end users. Audit's " "Audits have 'name' field now, that is more friendly to end users. Audit's "
"name can't exceed 63 characters." "name can't exceed 63 characters."
msgid ""
"Baremetal Model gets Audit scoper with an ability to exclude Ironic nodes."
msgstr ""
"Baremetal Model gets Audit scope with an ability to exclude Ironic nodes."
msgid "Bug Fixes" msgid "Bug Fixes"
msgstr "Bug Fixes" msgstr "Bug Fixes"
msgid ""
"Ceilometer Datasource has been deprecated since its API has been deprecated "
"in Ocata cycle. Watcher has supported Ceilometer for some releases after "
"Ocata to let users migrate to Gnocchi/Monasca datasources. Since Train "
"release, Ceilometer support will be removed."
msgstr ""
"Ceilometer Datasource has been deprecated since its API has been deprecated "
"in Ocata cycle. Watcher has supported Ceilometer for some releases after "
"Ocata to let users migrate to Gnocchi/Monasca datasources. Since Train "
"release, Ceilometer support will be removed."
msgid "Centralize all configuration options for Watcher." msgid "Centralize all configuration options for Watcher."
msgstr "Centralise all configuration options for Watcher." msgstr "Centralise all configuration options for Watcher."
msgid ""
"Check the creation time of the action plan, and set its state to SUPERSEDED "
"if it has expired."
msgstr ""
"Check the creation time of the action plan, and set its state to SUPERSEDED "
"if it has expired."
msgid "Contents:" msgid "Contents:"
msgstr "Contents:" msgstr "Contents:"
@@ -609,52 +360,6 @@ msgstr ""
"Now instances from particular project in OpenStack can be excluded from " "Now instances from particular project in OpenStack can be excluded from "
"audit defining scope in audit templates." "audit defining scope in audit templates."
msgid ""
"For a large cloud infrastructure, retrieving data from Nova may take a long "
"time. To avoid getting too much data from Nova, building the compute data "
"model according to the scope of audit."
msgstr ""
"For a large cloud infrastructure, retrieving data from Nova may take a long "
"time. To avoid getting too much data from Nova, building the compute data "
"model according to the scope of audit."
msgid ""
"Grafana has been added as datasource that can be used for collecting "
"metrics. The configuration options allow to specify what metrics and how "
"they are stored in grafana so that no matter how Grafana is configured it "
"can still be used. The configuration can be done via the typical "
"configuration file but it is recommended to configure most options in the "
"yaml file for metrics. For a complete walkthrough on configuring Grafana "
"see: https://docs.openstack.org/watcher/latest/datasources/grafana.html"
msgstr ""
"Grafana has been added as datasource that can be used for collecting "
"metrics. The configuration options allow to specify what metrics and how "
"they are stored in Grafana so that no matter how Grafana is configured it "
"can still be used. The configuration can be done via the typical "
"configuration file but it is recommended to configure most options in the "
"yaml file for metrics. For a complete walkthrough on configuring Grafana "
"see: https://docs.openstack.org/watcher/latest/datasources/grafana.html"
msgid ""
"If Gnocchi was configured to have a custom amount of retries and or a custom "
"timeout then the configuration needs to moved into the "
"`[watcher_datasources]` group instead of the `[gnocchi_client]` group."
msgstr ""
"If Gnocchi was configured to have a custom amount of retries and or a custom "
"timeout then the configuration needs to moved into the "
"`[watcher_datasources]` group instead of the `[gnocchi_client]` group."
msgid ""
"Improved interface for datasource baseclass that better defines expected "
"values and types for parameters and return types of all abstract methods. "
"This allows all strategies to work with every datasource provided the "
"metrics are configured for that given datasource."
msgstr ""
"Improved interface for datasource baseclass that better defines expected "
"values and types for parameters and return types of all abstract methods. "
"This allows all strategies to work with every datasource provided the "
"metrics are configured for that given datasource."
msgid "" msgid ""
"Instance cold migration logic is now replaced with using Nova migrate " "Instance cold migration logic is now replaced with using Nova migrate "
"Server(migrate Action) API which has host option since v2.56." "Server(migrate Action) API which has host option since v2.56."
@@ -662,17 +367,6 @@ msgstr ""
"Instance cold migration logic is now replaced with using Nova migrate " "Instance cold migration logic is now replaced with using Nova migrate "
"Server(migrate Action) API which has host option since v2.56." "Server(migrate Action) API which has host option since v2.56."
msgid ""
"Many operations in the decision engine will block on I/O. Such I/O "
"operations can stall the execution of a sequential application "
"significantly. To reduce the potential bottleneck of many operations the "
"general purpose decision engine threadpool is introduced."
msgstr ""
"Many operations in the decision engine will block on I/O. Such I/O "
"operations can stall the execution of a sequential application "
"significantly. To reduce the potential bottleneck of many operations the "
"general purpose decision engine threadpool is introduced."
msgid "New Features" msgid "New Features"
msgstr "New Features" msgstr "New Features"
@@ -695,13 +389,6 @@ msgstr ""
"Nova API version is now set to 2.56 by default. This needs the migrate " "Nova API version is now set to 2.56 by default. This needs the migrate "
"action of migration type cold with destination_node parameter to work." "action of migration type cold with destination_node parameter to work."
msgid ""
"Now Watcher strategy can select specific planner beyond default. Strategy "
"can set planner property to specify its own planner."
msgstr ""
"Now Watcher strategy can select specific planner beyond default. Strategy "
"can set planner property to specify its own planner."
msgid "Ocata Series Release Notes" msgid "Ocata Series Release Notes"
msgstr "Ocata Series Release Notes" msgstr "Ocata Series Release Notes"
@@ -742,77 +429,12 @@ msgstr ""
"resources will be called \"Audit scope\" and will be defined in each audit " "resources will be called \"Audit scope\" and will be defined in each audit "
"template (which contains the audit settings)." "template (which contains the audit settings)."
msgid ""
"Python 2.7 support has been dropped. Last release of Watcher to support "
"py2.7 is OpenStack Train. The minimum version of Python now supported by "
"Watcher is Python 3.6."
msgstr ""
"Python 2.7 support has been dropped. Last release of Watcher to support "
"py2.7 is OpenStack Train. The minimum version of Python now supported by "
"Watcher is Python 3.6."
msgid "Queens Series Release Notes" msgid "Queens Series Release Notes"
msgstr "Queens Series Release Notes" msgstr "Queens Series Release Notes"
msgid "Rocky Series Release Notes" msgid "Rocky Series Release Notes"
msgstr "Rocky Series Release Notes" msgstr "Rocky Series Release Notes"
msgid ""
"Several strategies have changed the `node` parameter to `compute_node` to be "
"better aligned with terminology. These strategies include "
"`basic_consolidation` and `workload_stabilzation`. The `node` parameter will "
"remain supported during Train release and will be removed in the subsequent "
"release."
msgstr ""
"Several strategies have changed the `node` parameter to `compute_node` to be "
"better aligned with terminology. These strategies include "
"`basic_consolidation` and `workload_stabilzation`. The `node` parameter will "
"remain supported during Train release and will be removed in the subsequent "
"release."
msgid ""
"Specific strategies can override this order and use datasources which are "
"not listed in the global preference."
msgstr ""
"Specific strategies can override this order and use datasources which are "
"not listed in the global preference."
msgid "Stein Series Release Notes"
msgstr "Stein Series Release Notes"
msgid ""
"The building of the compute (Nova) data model will be done using the "
"decision engine threadpool, thereby, significantly reducing the total time "
"required to build it."
msgstr ""
"The building of the compute (Nova) data model will be done using the "
"decision engine threadpool, thereby, significantly reducing the total time "
"required to build it."
msgid ""
"The configuration options for query retries in `[gnocchi_client]` are "
"deprecated and the option in `[watcher_datasources]` should now be used."
msgstr ""
"The configuration options for query retries in `[gnocchi_client]` are "
"deprecated and the option in `[watcher_datasources]` should now be used."
msgid ""
"The default value of ``[oslo_policy] policy_file`` config option has been "
"changed from ``policy.json`` to ``policy.yaml``. Operators who are utilizing "
"customized or previously generated static policy JSON files (which are not "
"needed by default), should generate new policy files or convert them in YAML "
"format. Use the `oslopolicy-convert-json-to-yaml <https://docs.openstack.org/"
"oslo.policy/latest/cli/oslopolicy-convert-json-to-yaml.html>`_ tool to "
"convert a JSON to YAML formatted policy file in backward compatible way."
msgstr ""
"The default value of ``[oslo_policy] policy_file`` config option has been "
"changed from ``policy.json`` to ``policy.yaml``. Operators who are utilizing "
"customized or previously generated static policy JSON files (which are not "
"needed by default), should generate new policy files or convert them in YAML "
"format. Use the `oslopolicy-convert-json-to-yaml <https://docs.openstack.org/"
"oslo.policy/latest/cli/oslopolicy-convert-json-to-yaml.html>`_ tool to "
"convert a JSON to YAML formatted policy file in backward compatible way."
msgid "" msgid ""
"The graph model describes how VMs are associated to compute hosts. This " "The graph model describes how VMs are associated to compute hosts. This "
"allows for seeing relationships upfront between the entities and hence can " "allows for seeing relationships upfront between the entities and hence can "
@@ -833,22 +455,6 @@ msgstr ""
"was fixed. Before fixing, it booted an instance in the service project as a " "was fixed. Before fixing, it booted an instance in the service project as a "
"migrated instance." "migrated instance."
msgid ""
"The minimum required version of the ``[nova_client]/api_version`` value is "
"now enforced to be ``2.56`` which is available since the Queens version of "
"the nova compute service."
msgstr ""
"The minimum required version of the ``[nova_client]/api_version`` value is "
"now enforced to be ``2.56`` which is available since the Queens version of "
"the Nova compute service."
msgid ""
"The new strategy baseclass has significant changes in method parameters and "
"any out-of-tree strategies will have to be adopted."
msgstr ""
"The new strategy baseclass has significant changes in method parameters and "
"any out-of-tree strategies will have to be adopted."
msgid "" msgid ""
"There is new ability to create Watcher continuous audits with cron interval. " "There is new ability to create Watcher continuous audits with cron interval. "
"It means you may use, for example, optional argument '--interval \"\\*/5 \\* " "It means you may use, for example, optional argument '--interval \"\\*/5 \\* "
@@ -862,45 +468,9 @@ msgstr ""
"best effort basis and therefore, we recommend you to use a minimal cron " "best effort basis and therefore, we recommend you to use a minimal cron "
"interval of at least one minute." "interval of at least one minute."
msgid "Train Series Release Notes"
msgstr "Train Series Release Notes"
msgid "Upgrade Notes" msgid "Upgrade Notes"
msgstr "Upgrade Notes" msgstr "Upgrade Notes"
msgid ""
"Use of JSON policy files was deprecated by the ``oslo.policy`` library "
"during the Victoria development cycle. As a result, this deprecation is "
"being noted in the Wallaby cycle with an anticipated future removal of "
"support by ``oslo.policy``. As such operators will need to convert to YAML "
"policy files. Please see the upgrade notes for details on migration of any "
"custom policy files."
msgstr ""
"Use of JSON policy files was deprecated by the ``oslo.policy`` library "
"during the Victoria development cycle. As a result, this deprecation is "
"being noted in the Wallaby cycle with an anticipated future removal of "
"support by ``oslo.policy``. As such operators will need to convert to YAML "
"policy files. Please see the upgrade notes for details on migration of any "
"custom policy files."
msgid ""
"Using ``watcher/api/app.wsgi`` script is deprecated and it will be removed "
"in U release. Please switch to automatically generated ``watcher-api-wsgi`` "
"script instead."
msgstr ""
"Using ``watcher/api/app.wsgi`` script is deprecated and it will be removed "
"in U release. Please switch to automatically generated ``watcher-api-wsgi`` "
"script instead."
msgid "Ussuri Series Release Notes"
msgstr "Ussuri Series Release Notes"
msgid "Victoria Series Release Notes"
msgstr "Victoria Series Release Notes"
msgid "Wallaby Series Release Notes"
msgstr "Wallaby Series Release Notes"
msgid "" msgid ""
"Watcher can continuously optimize the OpenStack cloud for a specific " "Watcher can continuously optimize the OpenStack cloud for a specific "
"strategy or goal by triggering an audit periodically which generates an " "strategy or goal by triggering an audit periodically which generates an "
@@ -910,15 +480,6 @@ msgstr ""
"strategy or goal by triggering an audit periodically which generates an " "strategy or goal by triggering an audit periodically which generates an "
"action plan and run it automatically." "action plan and run it automatically."
msgid ""
"Watcher can get resource information such as total, allocation ratio and "
"reserved information from Placement API. Now we add some new fields to the "
"Watcher Data Model:"
msgstr ""
"Watcher can get resource information such as total, allocation ratio and "
"reserved information from Placement API. Now we add some new fields to the "
"Watcher Data Model:"
msgid "" msgid ""
"Watcher can now run specific actions in parallel improving the performances " "Watcher can now run specific actions in parallel improving the performances "
"dramatically when executing an action plan." "dramatically when executing an action plan."
@@ -956,15 +517,6 @@ msgstr ""
"includes all instances. It filters excluded instances when migration during " "includes all instances. It filters excluded instances when migration during "
"the audit." "the audit."
msgid ""
"Watcher now supports configuring which datasource to use and in which order. "
"This configuration is done by specifying datasources in the "
"watcher_datasources section:"
msgstr ""
"Watcher now supports configuring which datasource to use and in which order. "
"This configuration is done by specifying datasources in the "
"watcher_datasources section:"
msgid "" msgid ""
"Watcher removes the support to Nova legacy notifications because of Nova " "Watcher removes the support to Nova legacy notifications because of Nova "
"will deprecate them." "will deprecate them."
@@ -1005,24 +557,9 @@ msgstr ""
"Watcher supports multiple metrics backend and relies on Ceilometer and " "Watcher supports multiple metrics backend and relies on Ceilometer and "
"Monasca." "Monasca."
msgid "We also add some new propeties:"
msgstr "We also add some new properties:"
msgid "Welcome to watcher's Release Notes documentation!" msgid "Welcome to watcher's Release Notes documentation!"
msgstr "Welcome to watcher's Release Notes documentation!" msgstr "Welcome to watcher's Release Notes documentation!"
msgid "Xena Series Release Notes"
msgstr "Xena Series Release Notes"
msgid "Yoga Series Release Notes"
msgstr "Yoga Series Release Notes"
msgid "Zed Series Release Notes"
msgstr "Zed Series Release Notes"
msgid "``[watcher_datasources] datasources = gnocchi,monasca,ceilometer``"
msgstr "``[watcher_datasources] datasources = gnocchi,monasca,ceilometer``"
msgid "" msgid ""
"all Watcher objects have been refactored to support OVO (oslo." "all Watcher objects have been refactored to support OVO (oslo."
"versionedobjects) which was a prerequisite step in order to implement " "versionedobjects) which was a prerequisite step in order to implement "
@@ -1032,21 +569,6 @@ msgstr ""
"versionedobjects) which was a prerequisite step in order to implement " "versionedobjects) which was a prerequisite step in order to implement "
"versioned notifications." "versioned notifications."
msgid ""
"disk_gb_capacity: The amount of disk, take allocation ratio into account, "
"but do not include reserved."
msgstr ""
"disk_gb_capacity: The amount of disk, take allocation ratio into account, "
"but do not include reserved."
msgid ""
"disk_gb_reserved: The amount of disk a node has reserved for its own use."
msgstr ""
"disk_gb_reserved: The amount of disk a node has reserved for its own use."
msgid "disk_ratio: Disk allocation ratio."
msgstr "disk_ratio: Disk allocation ratio."
msgid "instance.create.end" msgid "instance.create.end"
msgstr "instance.create.end" msgstr "instance.create.end"
@@ -1113,21 +635,6 @@ msgstr "instance.unshelve.end"
msgid "instance.update" msgid "instance.update"
msgstr "instance.update" msgstr "instance.update"
msgid ""
"memory_mb_capacity: The amount of memory, take allocation ratio into "
"account, but do not include reserved."
msgstr ""
"memory_mb_capacity: The amount of memory, take allocation ratio into "
"account, but do not include reserved."
msgid ""
"memory_mb_reserved: The amount of memory a node has reserved for its own use."
msgstr ""
"memory_mb_reserved: The amount of memory a node has reserved for its own use."
msgid "memory_ratio: Memory allocation ratio."
msgstr "memory_ratio: Memory allocation ratio."
msgid "new:" msgid "new:"
msgstr "new:" msgstr "new:"
@@ -1142,16 +649,3 @@ msgstr "service.delete"
msgid "service.update" msgid "service.update"
msgstr "service.update" msgstr "service.update"
msgid ""
"vcpu_capacity: The amount of vcpu, take allocation ratio into account, but "
"do not include reserved."
msgstr ""
"vcpu_capacity: The amount of vcpu, take allocation ratio into account, but "
"do not include reserved."
msgid "vcpu_ratio: CPU allocation ratio."
msgstr "vcpu_ratio: CPU allocation ratio."
msgid "vcpu_reserved: The amount of cpu a node has reserved for its own use."
msgstr "vcpu_reserved: The amount of CPU a node has reserved for its own use."

View File

@@ -0,0 +1,33 @@
# Gérald LONLAS <g.lonlas@gmail.com>, 2016. #zanata
msgid ""
msgstr ""
"Project-Id-Version: python-watcher\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-03-22 02:21+0000\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"PO-Revision-Date: 2016-10-22 06:44+0000\n"
"Last-Translator: Gérald LONLAS <g.lonlas@gmail.com>\n"
"Language-Team: French\n"
"Language: fr\n"
"X-Generator: Zanata 4.3.3\n"
"Plural-Forms: nplurals=2; plural=(n > 1)\n"
msgid "0.29.0"
msgstr "0.29.0"
msgid "Contents:"
msgstr "Contenu :"
msgid "Current Series Release Notes"
msgstr "Note de la release actuelle"
msgid "New Features"
msgstr "Nouvelles fonctionnalités"
msgid "Newton Series Release Notes"
msgstr "Note de release pour Newton"
msgid "Welcome to watcher's Release Notes documentation!"
msgstr "Bienvenue dans la documentation de la note de Release de Watcher"

View File

@@ -1,6 +0,0 @@
=============================
Victoria Series Release Notes
=============================
.. release-notes::
:branch: unmaintained/victoria

View File

@@ -1,6 +0,0 @@
============================
Wallaby Series Release Notes
============================
.. release-notes::
:branch: unmaintained/wallaby

View File

@@ -1,6 +0,0 @@
=========================
Xena Series Release Notes
=========================
.. release-notes::
:branch: unmaintained/xena

View File

@@ -1,6 +0,0 @@
=========================
Yoga Series Release Notes
=========================
.. release-notes::
:branch: unmaintained/yoga

View File

@@ -1,6 +0,0 @@
========================
Zed Series Release Notes
========================
.. release-notes::
:branch: unmaintained/zed

View File

@@ -1,8 +1,8 @@
# Requirements lower bounds listed here are our best effort to keep them up to # The order of packages is significant, because pip processes them in the order
# date but we do not test them so no guarantee of having them all correct. If # of appearance. Changing the order has an impact on the overall integration
# you find any incorrect lower bounds, let us know or propose a fix. # process, which may cause wedges in the gate later.
apscheduler>=3.5.1 # MIT License apscheduler>=3.5.1 # MIT License
eventlet>=0.27.0 # MIT
jsonpatch>=1.21 # BSD jsonpatch>=1.21 # BSD
keystoneauth1>=3.4.0 # Apache-2.0 keystoneauth1>=3.4.0 # Apache-2.0
jsonschema>=3.2.0 # MIT jsonschema>=3.2.0 # MIT
@@ -12,31 +12,31 @@ croniter>=0.3.20 # MIT License
os-resource-classes>=0.4.0 os-resource-classes>=0.4.0
oslo.concurrency>=3.26.0 # Apache-2.0 oslo.concurrency>=3.26.0 # Apache-2.0
oslo.cache>=1.29.0 # Apache-2.0 oslo.cache>=1.29.0 # Apache-2.0
oslo.config>=6.8.0 # Apache-2.0 oslo.config>=5.2.0 # Apache-2.0
oslo.context>=2.21.0 # Apache-2.0 oslo.context>=2.21.0 # Apache-2.0
oslo.db>=4.44.0 # Apache-2.0 oslo.db>=4.44.0 # Apache-2.0
oslo.i18n>=3.20.0 # Apache-2.0 oslo.i18n>=3.20.0 # Apache-2.0
oslo.log>=3.37.0 # Apache-2.0 oslo.log>=3.37.0 # Apache-2.0
oslo.messaging>=14.1.0 # Apache-2.0 oslo.messaging>=8.1.2 # Apache-2.0
oslo.policy>=4.5.0 # Apache-2.0 oslo.policy>=1.34.0 # Apache-2.0
oslo.reports>=1.27.0 # Apache-2.0 oslo.reports>=1.27.0 # Apache-2.0
oslo.serialization>=2.25.0 # Apache-2.0 oslo.serialization>=2.25.0 # Apache-2.0
oslo.service>=1.30.0 # Apache-2.0 oslo.service>=1.30.0 # Apache-2.0
oslo.upgradecheck>=1.3.0 # Apache-2.0 oslo.upgradecheck>=0.1.0 # Apache-2.0
oslo.utils>=7.0.0 # Apache-2.0 oslo.utils>=3.36.0 # Apache-2.0
oslo.versionedobjects>=1.32.0 # Apache-2.0 oslo.versionedobjects>=1.32.0 # Apache-2.0
PasteDeploy>=1.5.2 # MIT PasteDeploy>=1.5.2 # MIT
pbr>=3.1.1 # Apache-2.0 pbr>=3.1.1 # Apache-2.0
pecan>=1.3.2 # BSD pecan>=1.3.2 # BSD
PrettyTable>=0.7.2 # BSD PrettyTable<0.8,>=0.7.2 # BSD
gnocchiclient>=7.0.1 # Apache-2.0 gnocchiclient>=7.0.1 # Apache-2.0
python-ceilometerclient>=2.9.0 # Apache-2.0
python-cinderclient>=3.5.0 # Apache-2.0 python-cinderclient>=3.5.0 # Apache-2.0
python-glanceclient>=2.9.1 # Apache-2.0 python-glanceclient>=2.9.1 # Apache-2.0
python-keystoneclient>=3.15.0 # Apache-2.0 python-keystoneclient>=3.15.0 # Apache-2.0
python-monascaclient>=1.12.0 # Apache-2.0 python-monascaclient>=1.12.0 # Apache-2.0
python-neutronclient>=6.7.0 # Apache-2.0 python-neutronclient>=6.7.0 # Apache-2.0
python-novaclient>=14.1.0 # Apache-2.0 python-novaclient>=14.1.0 # Apache-2.0
python-observabilityclient>=0.3.0 # Apache-2.0
python-openstackclient>=3.14.0 # Apache-2.0 python-openstackclient>=3.14.0 # Apache-2.0
python-ironicclient>=2.5.0 # Apache-2.0 python-ironicclient>=2.5.0 # Apache-2.0
SQLAlchemy>=1.2.5 # MIT SQLAlchemy>=1.2.5 # MIT

View File

@@ -1,12 +1,12 @@
[metadata] [metadata]
name = python-watcher name = python-watcher
summary = OpenStack Watcher provides a flexible and scalable resource optimization service for multi-tenant OpenStack-based clouds. summary = OpenStack Watcher provides a flexible and scalable resource optimization service for multi-tenant OpenStack-based clouds.
description_file = description-file =
README.rst README.rst
author = OpenStack author = OpenStack
author_email = openstack-discuss@lists.openstack.org author-email = openstack-discuss@lists.openstack.org
home_page = https://docs.openstack.org/watcher/latest/ home-page = https://docs.openstack.org/watcher/latest/
python_requires = >=3.9 python-requires = >=3.6
classifier = classifier =
Environment :: OpenStack Environment :: OpenStack
Intended Audience :: Information Technology Intended Audience :: Information Technology
@@ -17,10 +17,9 @@ classifier =
Programming Language :: Python :: Implementation :: CPython Programming Language :: Python :: Implementation :: CPython
Programming Language :: Python :: 3 :: Only Programming Language :: Python :: 3 :: Only
Programming Language :: Python :: 3 Programming Language :: Python :: 3
Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.6
Programming Language :: Python :: 3.10 Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.11 Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.12
[files] [files]
packages = packages =
@@ -109,8 +108,3 @@ watcher_cluster_data_model_collectors =
compute = watcher.decision_engine.model.collector.nova:NovaClusterDataModelCollector compute = watcher.decision_engine.model.collector.nova:NovaClusterDataModelCollector
storage = watcher.decision_engine.model.collector.cinder:CinderClusterDataModelCollector storage = watcher.decision_engine.model.collector.cinder:CinderClusterDataModelCollector
baremetal = watcher.decision_engine.model.collector.ironic:BaremetalClusterDataModelCollector baremetal = watcher.decision_engine.model.collector.ironic:BaremetalClusterDataModelCollector
[codespell]
skip = *.po,*.js,*.css,*.html,*.svg,HACKING.py,*hacking*,*build*,*_static*,doc/dictionary.txt,*.pyc,*.inv,*.gz,*.jpg,*.png,*.vsd,*.graffle,*.json
count =
quiet-level = 4

View File

@@ -1,7 +1,15 @@
# The order of packages is significant, because pip processes them in the order
# of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later.
coverage>=4.5.1 # Apache-2.0 coverage>=4.5.1 # Apache-2.0
doc8>=0.8.0 # Apache-2.0
freezegun>=0.3.10 # Apache-2.0 freezegun>=0.3.10 # Apache-2.0
hacking>=3.0.1,<3.1.0 # Apache-2.0
oslotest>=3.3.0 # Apache-2.0 oslotest>=3.3.0 # Apache-2.0
os-testr>=1.0.0 # Apache-2.0
testscenarios>=0.5.0 # Apache-2.0/BSD testscenarios>=0.5.0 # Apache-2.0/BSD
testtools>=2.3.0 # MIT testtools>=2.3.0 # MIT
stestr>=2.0.0 # Apache-2.0 stestr>=2.0.0 # Apache-2.0
WebTest>=2.0.27 # MIT os-api-ref>=1.4.0 # Apache-2.0
bandit>=1.6.0 # Apache-2.0

99
tox.ini
View File

@@ -1,55 +1,37 @@
[tox] [tox]
minversion = 3.18.0 minversion = 2.0
envlist = py3,pep8 envlist = py36,py37,pep8
skipsdist = True
ignore_basepython_conflict = True ignore_basepython_conflict = True
[testenv] [testenv]
basepython = python3 basepython = python3
usedevelop = True usedevelop = True
allowlist_externals = find whitelist_externals = find
rm rm
install_command = pip install -c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master} {opts} {packages} install_command = pip install {opts} {packages}
setenv = setenv =
VIRTUAL_ENV={envdir} VIRTUAL_ENV={envdir}
OS_STDOUT_CAPTURE=1
OS_STDERR_CAPTURE=1
OS_TEST_TIMEOUT=30
PYTHONDONTWRITEBYTECODE=1
deps = deps =
-c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/victoria}
-r{toxinidir}/test-requirements.txt -r{toxinidir}/test-requirements.txt
-r{toxinidir}/requirements.txt -r{toxinidir}/requirements.txt
python-libmaas>=0.6.8
commands = commands =
rm -f .testrepository/times.dbm rm -f .testrepository/times.dbm
find . -type f -name "*.py[c|o]" -delete find . -type f -name "*.py[c|o]" -delete
stestr run {posargs} stestr run {posargs}
passenv = passenv = http_proxy HTTP_PROXY https_proxy HTTPS_PROXY no_proxy NO_PROXY
http_proxy
HTTP_PROXY
https_proxy
HTTPS_PROXY
no_proxy
NO_PROXY
OS_DEBUG
# NOTE(sean-k-mooney) optimization is enabled by default and when enabled
# asserts are complied out. Disable optimization to allow asserts in
# nova to fire in unit and functional tests. This can be useful for
# debugging issue with fixtures and mocks.
PYTHONOPTIMIZE
[testenv:pep8] [testenv:pep8]
description =
Run style checks.
skip_install = true
deps =
pre-commit
commands = commands =
pre-commit run --all-files --show-diff-on-failure doc8 doc/source/ CONTRIBUTING.rst HACKING.rst README.rst
flake8
bandit -r watcher -x watcher/tests/* -n5 -ll -s B320,B322
[testenv:venv] [testenv:venv]
setenv = PYTHONHASHSEED=0 setenv = PYTHONHASHSEED=0
deps = deps =
-c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/victoria}
-r{toxinidir}/doc/requirements.txt -r{toxinidir}/doc/requirements.txt
-r{toxinidir}/test-requirements.txt -r{toxinidir}/test-requirements.txt
-r{toxinidir}/requirements.txt -r{toxinidir}/requirements.txt
@@ -67,15 +49,14 @@ commands =
[testenv:docs] [testenv:docs]
setenv = PYTHONHASHSEED=0 setenv = PYTHONHASHSEED=0
deps = deps = -r{toxinidir}/doc/requirements.txt
-r{toxinidir}/doc/requirements.txt
commands = commands =
rm -fr doc/build doc/source/api/ .autogenerated rm -fr doc/build doc/source/api/ .autogenerated
sphinx-build -W --keep-going -b html doc/source doc/build/html sphinx-build -W --keep-going -b html doc/source doc/build/html
[testenv:api-ref] [testenv:api-ref]
deps = -r{toxinidir}/doc/requirements.txt deps = -r{toxinidir}/doc/requirements.txt
allowlist_externals = bash whitelist_externals = bash
commands = commands =
bash -c 'rm -rf api-ref/build' bash -c 'rm -rf api-ref/build'
sphinx-build -W --keep-going -b html -d api-ref/build/doctrees api-ref/source api-ref/build/html sphinx-build -W --keep-going -b html -d api-ref/build/doctrees api-ref/source api-ref/build/html
@@ -92,29 +73,6 @@ commands =
commands = commands =
oslopolicy-sample-generator --config-file etc/watcher/oslo-policy-generator/watcher-policy-generator.conf oslopolicy-sample-generator --config-file etc/watcher/oslo-policy-generator/watcher-policy-generator.conf
[testenv:wheel]
commands = python setup.py bdist_wheel
[testenv:pdf-docs]
deps = {[testenv:docs]deps}
allowlist_externals =
rm
make
commands =
rm -rf doc/build/pdf
sphinx-build -W --keep-going -b latex doc/source doc/build/pdf
make -C doc/build/pdf
[testenv:releasenotes]
deps = -r{toxinidir}/doc/requirements.txt
commands = sphinx-build -a -W -E -d releasenotes/build/doctrees --keep-going -b html releasenotes/source releasenotes/build/html
[testenv:bandit]
skip_install = true
deps = {[testenv:pep8]deps}
commands =
pre-commit run --all-files --show-diff-on-failure bandit
[flake8] [flake8]
filename = *.py,app.wsgi filename = *.py,app.wsgi
show-source=True show-source=True
@@ -124,6 +82,9 @@ builtins= _
enable-extensions = H106,H203,H904 enable-extensions = H106,H203,H904
exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build,*sqlalchemy/alembic/versions/*,demo/,releasenotes exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build,*sqlalchemy/alembic/versions/*,demo/,releasenotes
[testenv:wheel]
commands = python setup.py bdist_wheel
[hacking] [hacking]
import_exceptions = watcher._i18n import_exceptions = watcher._i18n
@@ -147,7 +108,33 @@ extension =
N366 = checks:import_stock_mock N366 = checks:import_stock_mock
paths = ./watcher/hacking paths = ./watcher/hacking
[doc8] [doc8]
extension=.rst extension=.rst
# todo: stop ignoring doc/source/man when https://bugs.launchpad.net/doc8/+bug/1502391 is fixed # todo: stop ignoring doc/source/man when https://bugs.launchpad.net/doc8/+bug/1502391 is fixed
ignore-path=doc/source/image_src,doc/source/man,doc/source/api ignore-path=doc/source/image_src,doc/source/man,doc/source/api
[testenv:pdf-docs]
envdir = {toxworkdir}/docs
deps = {[testenv:docs]deps}
whitelist_externals =
rm
make
commands =
rm -rf doc/build/pdf
sphinx-build -W --keep-going -b latex doc/source doc/build/pdf
make -C doc/build/pdf
[testenv:releasenotes]
deps = -r{toxinidir}/doc/requirements.txt
commands = sphinx-build -a -W -E -d releasenotes/build/doctrees --keep-going -b html releasenotes/source releasenotes/build/html
[testenv:bandit]
deps = -r{toxinidir}/test-requirements.txt
commands = bandit -r watcher -x watcher/tests/* -n5 -ll -s B320
[testenv:lower-constraints]
deps =
-c{toxinidir}/lower-constraints.txt
-r{toxinidir}/test-requirements.txt
-r{toxinidir}/requirements.txt

View File

@@ -55,8 +55,8 @@ possible to :ref:`develop new implementations <implement_action_plugin>` which
are dynamically loaded by Watcher at launch time. are dynamically loaded by Watcher at launch time.
""" """
from http import HTTPStatus import datetime
from oslo_utils import timeutils
import pecan import pecan
from pecan import rest from pecan import rest
import wsme import wsme
@@ -193,9 +193,9 @@ class Action(base.APIBase):
sample = cls(uuid='27e3153e-d5bf-4b7e-b517-fb518e17f34c', sample = cls(uuid='27e3153e-d5bf-4b7e-b517-fb518e17f34c',
description='action description', description='action description',
state='PENDING', state='PENDING',
created_at=timeutils.utcnow(), created_at=datetime.datetime.utcnow(),
deleted_at=None, deleted_at=None,
updated_at=timeutils.utcnow(), updated_at=datetime.datetime.utcnow(),
parents=[]) parents=[])
sample._action_plan_uuid = '7ae81bb3-dec3-4289-8d6c-da80bd8001ae' sample._action_plan_uuid = '7ae81bb3-dec3-4289-8d6c-da80bd8001ae'
return cls._convert_with_links(sample, 'http://localhost:9322', expand) return cls._convert_with_links(sample, 'http://localhost:9322', expand)
@@ -229,7 +229,6 @@ class ActionCollection(collection.Collection):
class ActionsController(rest.RestController): class ActionsController(rest.RestController):
"""REST controller for Actions.""" """REST controller for Actions."""
def __init__(self): def __init__(self):
super(ActionsController, self).__init__() super(ActionsController, self).__init__()
@@ -334,7 +333,7 @@ class ActionsController(rest.RestController):
policy.enforce(context, 'action:detail', policy.enforce(context, 'action:detail',
action='action:detail') action='action:detail')
# NOTE(lucasagomes): /detail should only work against collections # NOTE(lucasagomes): /detail should only work agaist collections
parent = pecan.request.path.split('/')[:-1][-1] parent = pecan.request.path.split('/')[:-1][-1]
if parent != "actions": if parent != "actions":
raise exception.HTTPNotFound raise exception.HTTPNotFound
@@ -363,7 +362,7 @@ class ActionsController(rest.RestController):
return Action.convert_with_links(action) return Action.convert_with_links(action)
@wsme_pecan.wsexpose(Action, body=Action, status_code=HTTPStatus.CREATED) @wsme_pecan.wsexpose(Action, body=Action, status_code=201)
def post(self, action): def post(self, action):
"""Create a new action(forbidden). """Create a new action(forbidden).
@@ -423,7 +422,7 @@ class ActionsController(rest.RestController):
action_to_update.save() action_to_update.save()
return Action.convert_with_links(action_to_update) return Action.convert_with_links(action_to_update)
@wsme_pecan.wsexpose(None, types.uuid, status_code=HTTPStatus.NO_CONTENT) @wsme_pecan.wsexpose(None, types.uuid, status_code=204)
def delete(self, action_uuid): def delete(self, action_uuid):
"""Delete a action(forbidden). """Delete a action(forbidden).

View File

@@ -54,9 +54,9 @@ To see the life-cycle and description of
state machine <action_plan_state_machine>`. state machine <action_plan_state_machine>`.
""" """
from http import HTTPStatus import datetime
from oslo_log import log from oslo_log import log
from oslo_utils import timeutils
import pecan import pecan
from pecan import rest from pecan import rest
import wsme import wsme
@@ -292,9 +292,9 @@ class ActionPlan(base.APIBase):
def sample(cls, expand=True): def sample(cls, expand=True):
sample = cls(uuid='9ef4d84c-41e8-4418-9220-ce55be0436af', sample = cls(uuid='9ef4d84c-41e8-4418-9220-ce55be0436af',
state='ONGOING', state='ONGOING',
created_at=timeutils.utcnow(), created_at=datetime.datetime.utcnow(),
deleted_at=None, deleted_at=None,
updated_at=timeutils.utcnow()) updated_at=datetime.datetime.utcnow())
sample._audit_uuid = 'abcee106-14d3-4515-b744-5a26885cf6f6' sample._audit_uuid = 'abcee106-14d3-4515-b744-5a26885cf6f6'
sample._efficacy_indicators = [{'description': 'Test indicator', sample._efficacy_indicators = [{'description': 'Test indicator',
'name': 'test_indicator', 'name': 'test_indicator',
@@ -433,7 +433,7 @@ class ActionPlansController(rest.RestController):
policy.enforce(context, 'action_plan:detail', policy.enforce(context, 'action_plan:detail',
action='action_plan:detail') action='action_plan:detail')
# NOTE(lucasagomes): /detail should only work against collections # NOTE(lucasagomes): /detail should only work agaist collections
parent = pecan.request.path.split('/')[:-1][-1] parent = pecan.request.path.split('/')[:-1][-1]
if parent != "action_plans": if parent != "action_plans":
raise exception.HTTPNotFound raise exception.HTTPNotFound
@@ -460,7 +460,7 @@ class ActionPlansController(rest.RestController):
return ActionPlan.convert_with_links(action_plan) return ActionPlan.convert_with_links(action_plan)
@wsme_pecan.wsexpose(None, types.uuid, status_code=HTTPStatus.NO_CONTENT) @wsme_pecan.wsexpose(None, types.uuid, status_code=204)
def delete(self, action_plan_uuid): def delete(self, action_plan_uuid):
"""Delete an action plan. """Delete an action plan.

View File

@@ -32,9 +32,6 @@ states, visit :ref:`the Audit State machine <audit_state_machine>`.
import datetime import datetime
from dateutil import tz from dateutil import tz
from http import HTTPStatus
from oslo_log import log
from oslo_utils import timeutils
import pecan import pecan
from pecan import rest from pecan import rest
import wsme import wsme
@@ -42,6 +39,8 @@ from wsme import types as wtypes
from wsme import utils as wutils from wsme import utils as wutils
import wsmeext.pecan as wsme_pecan import wsmeext.pecan as wsme_pecan
from oslo_log import log
from watcher._i18n import _ from watcher._i18n import _
from watcher.api.controllers import base from watcher.api.controllers import base
from watcher.api.controllers import link from watcher.api.controllers import link
@@ -171,16 +170,16 @@ class AuditPostType(wtypes.Base):
strategy = _get_object_by_value(context, objects.Strategy, strategy = _get_object_by_value(context, objects.Strategy,
self.strategy) self.strategy)
self.name = "%s-%s" % (strategy.name, self.name = "%s-%s" % (strategy.name,
timeutils.utcnow().isoformat()) datetime.datetime.utcnow().isoformat())
elif self.audit_template_uuid: elif self.audit_template_uuid:
audit_template = objects.AuditTemplate.get( audit_template = objects.AuditTemplate.get(
context, self.audit_template_uuid) context, self.audit_template_uuid)
self.name = "%s-%s" % (audit_template.name, self.name = "%s-%s" % (audit_template.name,
timeutils.utcnow().isoformat()) datetime.datetime.utcnow().isoformat())
else: else:
goal = _get_object_by_value(context, objects.Goal, self.goal) goal = _get_object_by_value(context, objects.Goal, self.goal)
self.name = "%s-%s" % (goal.name, self.name = "%s-%s" % (goal.name,
timeutils.utcnow().isoformat()) datetime.datetime.utcnow().isoformat())
# No more than 63 characters # No more than 63 characters
if len(self.name) > 63: if len(self.name) > 63:
LOG.warning("Audit: %s length exceeds 63 characters", LOG.warning("Audit: %s length exceeds 63 characters",
@@ -424,15 +423,15 @@ class Audit(base.APIBase):
name='My Audit', name='My Audit',
audit_type='ONESHOT', audit_type='ONESHOT',
state='PENDING', state='PENDING',
created_at=timeutils.utcnow(), created_at=datetime.datetime.utcnow(),
deleted_at=None, deleted_at=None,
updated_at=timeutils.utcnow(), updated_at=datetime.datetime.utcnow(),
interval='7200', interval='7200',
scope=[], scope=[],
auto_trigger=False, auto_trigger=False,
next_run_time=timeutils.utcnow(), next_run_time=datetime.datetime.utcnow(),
start_time=timeutils.utcnow(), start_time=datetime.datetime.utcnow(),
end_time=timeutils.utcnow()) end_time=datetime.datetime.utcnow())
sample.goal_id = '7ae81bb3-dec3-4289-8d6c-da80bd8001ae' sample.goal_id = '7ae81bb3-dec3-4289-8d6c-da80bd8001ae'
sample.strategy_id = '7ae81bb3-dec3-4289-8d6c-da80bd8001ff' sample.strategy_id = '7ae81bb3-dec3-4289-8d6c-da80bd8001ff'
@@ -468,7 +467,6 @@ class AuditCollection(collection.Collection):
class AuditsController(rest.RestController): class AuditsController(rest.RestController):
"""REST controller for Audits.""" """REST controller for Audits."""
def __init__(self): def __init__(self):
super(AuditsController, self).__init__() super(AuditsController, self).__init__()
self.dc_client = rpcapi.DecisionEngineAPI() self.dc_client = rpcapi.DecisionEngineAPI()
@@ -570,7 +568,7 @@ class AuditsController(rest.RestController):
context = pecan.request.context context = pecan.request.context
policy.enforce(context, 'audit:detail', policy.enforce(context, 'audit:detail',
action='audit:detail') action='audit:detail')
# NOTE(lucasagomes): /detail should only work against collections # NOTE(lucasagomes): /detail should only work agaist collections
parent = pecan.request.path.split('/')[:-1][-1] parent = pecan.request.path.split('/')[:-1][-1]
if parent != "audits": if parent != "audits":
raise exception.HTTPNotFound raise exception.HTTPNotFound
@@ -597,8 +595,7 @@ class AuditsController(rest.RestController):
return Audit.convert_with_links(rpc_audit) return Audit.convert_with_links(rpc_audit)
@wsme_pecan.wsexpose(Audit, body=AuditPostType, @wsme_pecan.wsexpose(Audit, body=AuditPostType, status_code=201)
status_code=HTTPStatus.CREATED)
def post(self, audit_p): def post(self, audit_p):
"""Create a new audit. """Create a new audit.
@@ -720,7 +717,7 @@ class AuditsController(rest.RestController):
audit_to_update.save() audit_to_update.save()
return Audit.convert_with_links(audit_to_update) return Audit.convert_with_links(audit_to_update)
@wsme_pecan.wsexpose(None, wtypes.text, status_code=HTTPStatus.NO_CONTENT) @wsme_pecan.wsexpose(None, wtypes.text, status_code=204)
def delete(self, audit): def delete(self, audit):
"""Delete an audit. """Delete an audit.

View File

@@ -43,8 +43,8 @@ will be launched automatically or will need a manual confirmation from the
:ref:`Administrator <administrator_definition>`. :ref:`Administrator <administrator_definition>`.
""" """
from http import HTTPStatus import datetime
from oslo_utils import timeutils
import pecan import pecan
from pecan import rest from pecan import rest
import wsme import wsme
@@ -439,9 +439,9 @@ class AuditTemplate(base.APIBase):
description='Description of my audit template', description='Description of my audit template',
goal_uuid='83e44733-b640-40e2-8d8a-7dd3be7134e6', goal_uuid='83e44733-b640-40e2-8d8a-7dd3be7134e6',
strategy_uuid='367d826e-b6a4-4b70-bc44-c3f6fe1c9986', strategy_uuid='367d826e-b6a4-4b70-bc44-c3f6fe1c9986',
created_at=timeutils.utcnow(), created_at=datetime.datetime.utcnow(),
deleted_at=None, deleted_at=None,
updated_at=timeutils.utcnow(), updated_at=datetime.datetime.utcnow(),
scope=[],) scope=[],)
return cls._convert_with_links(sample, 'http://localhost:9322', expand) return cls._convert_with_links(sample, 'http://localhost:9322', expand)
@@ -475,7 +475,6 @@ class AuditTemplateCollection(collection.Collection):
class AuditTemplatesController(rest.RestController): class AuditTemplatesController(rest.RestController):
"""REST controller for AuditTemplates.""" """REST controller for AuditTemplates."""
def __init__(self): def __init__(self):
super(AuditTemplatesController, self).__init__() super(AuditTemplatesController, self).__init__()
@@ -576,7 +575,7 @@ class AuditTemplatesController(rest.RestController):
policy.enforce(context, 'audit_template:detail', policy.enforce(context, 'audit_template:detail',
action='audit_template:detail') action='audit_template:detail')
# NOTE(lucasagomes): /detail should only work against collections # NOTE(lucasagomes): /detail should only work agaist collections
parent = pecan.request.path.split('/')[:-1][-1] parent = pecan.request.path.split('/')[:-1][-1]
if parent != "audit_templates": if parent != "audit_templates":
raise exception.HTTPNotFound raise exception.HTTPNotFound
@@ -619,7 +618,7 @@ class AuditTemplatesController(rest.RestController):
@wsme.validate(types.uuid, AuditTemplatePostType) @wsme.validate(types.uuid, AuditTemplatePostType)
@wsme_pecan.wsexpose(AuditTemplate, body=AuditTemplatePostType, @wsme_pecan.wsexpose(AuditTemplate, body=AuditTemplatePostType,
status_code=HTTPStatus.CREATED) status_code=201)
def post(self, audit_template_postdata): def post(self, audit_template_postdata):
"""Create a new audit template. """Create a new audit template.
@@ -695,7 +694,7 @@ class AuditTemplatesController(rest.RestController):
audit_template_to_update.save() audit_template_to_update.save()
return AuditTemplate.convert_with_links(audit_template_to_update) return AuditTemplate.convert_with_links(audit_template_to_update)
@wsme_pecan.wsexpose(None, wtypes.text, status_code=HTTPStatus.NO_CONTENT) @wsme_pecan.wsexpose(None, wtypes.text, status_code=204)
def delete(self, audit_template): def delete(self, audit_template):
"""Delete a audit template. """Delete a audit template.

View File

@@ -32,7 +32,6 @@ from watcher.decision_engine import rpcapi
class DataModelController(rest.RestController): class DataModelController(rest.RestController):
"""REST controller for data model""" """REST controller for data model"""
def __init__(self): def __init__(self):
super(DataModelController, self).__init__() super(DataModelController, self).__init__()

View File

@@ -24,7 +24,7 @@ Here are some examples of :ref:`Goals <goal_definition>`:
- minimize the energy consumption - minimize the energy consumption
- minimize the number of compute nodes (consolidation) - minimize the number of compute nodes (consolidation)
- balance the workload among compute nodes - balance the workload among compute nodes
- minimize the license cost (some software have a licensing model which is - minimize the license cost (some softwares have a licensing model which is
based on the number of sockets or cores where the software is deployed) based on the number of sockets or cores where the software is deployed)
- find the most appropriate moment for a planned maintenance on a - find the most appropriate moment for a planned maintenance on a
given group of host (which may be an entire availability zone): given group of host (which may be an entire availability zone):
@@ -153,7 +153,6 @@ class GoalCollection(collection.Collection):
class GoalsController(rest.RestController): class GoalsController(rest.RestController):
"""REST controller for Goals.""" """REST controller for Goals."""
def __init__(self): def __init__(self):
super(GoalsController, self).__init__() super(GoalsController, self).__init__()
@@ -217,7 +216,7 @@ class GoalsController(rest.RestController):
context = pecan.request.context context = pecan.request.context
policy.enforce(context, 'goal:detail', policy.enforce(context, 'goal:detail',
action='goal:detail') action='goal:detail')
# NOTE(lucasagomes): /detail should only work against collections # NOTE(lucasagomes): /detail should only work agaist collections
parent = pecan.request.path.split('/')[:-1][-1] parent = pecan.request.path.split('/')[:-1][-1]
if parent != "goals": if parent != "goals":
raise exception.HTTPNotFound raise exception.HTTPNotFound

View File

@@ -145,7 +145,6 @@ class ScoringEngineCollection(collection.Collection):
class ScoringEngineController(rest.RestController): class ScoringEngineController(rest.RestController):
"""REST controller for Scoring Engines.""" """REST controller for Scoring Engines."""
def __init__(self): def __init__(self):
super(ScoringEngineController, self).__init__() super(ScoringEngineController, self).__init__()

View File

@@ -19,6 +19,8 @@ Service mechanism provides ability to monitor Watcher services state.
""" """
import datetime import datetime
import six
from oslo_config import cfg from oslo_config import cfg
from oslo_log import log from oslo_log import log
from oslo_utils import timeutils from oslo_utils import timeutils
@@ -68,7 +70,7 @@ class Service(base.APIBase):
service = objects.Service.get(pecan.request.context, id) service = objects.Service.get(pecan.request.context, id)
last_heartbeat = (service.last_seen_up or service.updated_at or last_heartbeat = (service.last_seen_up or service.updated_at or
service.created_at) service.created_at)
if isinstance(last_heartbeat, str): if isinstance(last_heartbeat, six.string_types):
# NOTE(russellb) If this service came in over rpc via # NOTE(russellb) If this service came in over rpc via
# conductor, then the timestamp will be a string and needs to be # conductor, then the timestamp will be a string and needs to be
# converted back to a datetime. # converted back to a datetime.
@@ -175,7 +177,6 @@ class ServiceCollection(collection.Collection):
class ServicesController(rest.RestController): class ServicesController(rest.RestController):
"""REST controller for Services.""" """REST controller for Services."""
def __init__(self): def __init__(self):
super(ServicesController, self).__init__() super(ServicesController, self).__init__()
@@ -237,7 +238,7 @@ class ServicesController(rest.RestController):
context = pecan.request.context context = pecan.request.context
policy.enforce(context, 'service:detail', policy.enforce(context, 'service:detail',
action='service:detail') action='service:detail')
# NOTE(lucasagomes): /detail should only work against collections # NOTE(lucasagomes): /detail should only work agaist collections
parent = pecan.request.path.split('/')[:-1][-1] parent = pecan.request.path.split('/')[:-1][-1]
if parent != "services": if parent != "services":
raise exception.HTTPNotFound raise exception.HTTPNotFound

View File

@@ -196,7 +196,6 @@ class StrategyCollection(collection.Collection):
class StrategiesController(rest.RestController): class StrategiesController(rest.RestController):
"""REST controller for Strategies.""" """REST controller for Strategies."""
def __init__(self): def __init__(self):
super(StrategiesController, self).__init__() super(StrategiesController, self).__init__()
@@ -284,7 +283,7 @@ class StrategiesController(rest.RestController):
context = pecan.request.context context = pecan.request.context
policy.enforce(context, 'strategy:detail', policy.enforce(context, 'strategy:detail',
action='strategy:detail') action='strategy:detail')
# NOTE(lucasagomes): /detail should only work against collections # NOTE(lucasagomes): /detail should only work agaist collections
parent = pecan.request.path.split('/')[:-1][-1] parent = pecan.request.path.split('/')[:-1][-1]
if parent != "strategies": if parent != "strategies":
raise exception.HTTPNotFound raise exception.HTTPNotFound

View File

@@ -15,6 +15,7 @@
from oslo_serialization import jsonutils from oslo_serialization import jsonutils
from oslo_utils import strutils from oslo_utils import strutils
import six
import wsme import wsme
from wsme import types as wtypes from wsme import types as wtypes
@@ -131,7 +132,7 @@ class JsonType(wtypes.UserType):
def __str__(self): def __str__(self):
# These are the json serializable native types # These are the json serializable native types
return ' | '.join(map(str, (wtypes.text, int, float, return ' | '.join(map(str, (wtypes.text, six.integer_types, float,
BooleanType, list, dict, None))) BooleanType, list, dict, None)))
@staticmethod @staticmethod
@@ -161,7 +162,6 @@ class MultiType(wtypes.UserType):
:param types: Variable-length list of types. :param types: Variable-length list of types.
""" """
def __init__(self, *types): def __init__(self, *types):
self.types = types self.types = types

View File

@@ -14,7 +14,6 @@
Webhook endpoint for Watcher v1 REST API. Webhook endpoint for Watcher v1 REST API.
""" """
from http import HTTPStatus
from oslo_log import log from oslo_log import log
import pecan import pecan
from pecan import rest from pecan import rest
@@ -32,13 +31,12 @@ LOG = log.getLogger(__name__)
class WebhookController(rest.RestController): class WebhookController(rest.RestController):
"""REST controller for webhooks resource.""" """REST controller for webhooks resource."""
def __init__(self): def __init__(self):
super(WebhookController, self).__init__() super(WebhookController, self).__init__()
self.dc_client = rpcapi.DecisionEngineAPI() self.dc_client = rpcapi.DecisionEngineAPI()
@wsme_pecan.wsexpose(None, wtypes.text, body=types.jsontype, @wsme_pecan.wsexpose(None, wtypes.text, body=types.jsontype,
status_code=HTTPStatus.ACCEPTED) status_code=202)
def post(self, audit_ident, body): def post(self, audit_ident, body):
"""Trigger the given audit. """Trigger the given audit.

View File

@@ -15,7 +15,7 @@
# under the License. # under the License.
from http import HTTPStatus from http import client as http_client
from oslo_config import cfg from oslo_config import cfg
from pecan import hooks from pecan import hooks
@@ -83,7 +83,6 @@ class NoExceptionTracebackHook(hooks.PecanHook):
# 'on_error' never fired for wsme+pecan pair. wsme @wsexpose decorator # 'on_error' never fired for wsme+pecan pair. wsme @wsexpose decorator
# catches and handles all the errors, so 'on_error' dedicated for unhandled # catches and handles all the errors, so 'on_error' dedicated for unhandled
# exceptions never fired. # exceptions never fired.
def after(self, state): def after(self, state):
# Omit empty body. Some errors may not have body at this level yet. # Omit empty body. Some errors may not have body at this level yet.
if not state.response.body: if not state.response.body:
@@ -92,8 +91,8 @@ class NoExceptionTracebackHook(hooks.PecanHook):
# Do nothing if there is no error. # Do nothing if there is no error.
# Status codes in the range 200 (OK) to 399 (400 = BAD_REQUEST) are not # Status codes in the range 200 (OK) to 399 (400 = BAD_REQUEST) are not
# an error. # an error.
if (HTTPStatus.OK <= state.response.status_int < if (http_client.OK <= state.response.status_int <
HTTPStatus.BAD_REQUEST): http_client.BAD_REQUEST):
return return
json_body = state.response.json json_body = state.response.json

View File

@@ -33,7 +33,6 @@ class AuthTokenMiddleware(auth_token.AuthProtocol):
for public routes in the API. for public routes in the API.
""" """
def __init__(self, app, conf, public_api_routes=()): def __init__(self, app, conf, public_api_routes=()):
route_pattern_tpl = r'%s(\.json|\.xml)?$' route_pattern_tpl = r'%s(\.json|\.xml)?$'

View File

@@ -118,8 +118,7 @@ class BaseAction(loadable.Loadable, metaclass=abc.ABCMeta):
""" """
raise NotImplementedError() raise NotImplementedError()
@property @abc.abstractproperty
@abc.abstractmethod
def schema(self): def schema(self):
"""Defines a Schema that the input parameters shall comply to """Defines a Schema that the input parameters shall comply to

View File

@@ -17,17 +17,17 @@
# limitations under the License. # limitations under the License.
# #
import enum
import time import time
from oslo_log import log
from watcher._i18n import _ from watcher._i18n import _
from watcher.applier.actions import base from watcher.applier.actions import base
from watcher.common import exception from watcher.common import exception
from watcher.common.metal_helper import constants as metal_constants
from watcher.common.metal_helper import factory as metal_helper_factory
LOG = log.getLogger(__name__)
class NodeState(enum.Enum):
POWERON = 'on'
POWEROFF = 'off'
class ChangeNodePowerState(base.BaseAction): class ChangeNodePowerState(base.BaseAction):
@@ -43,8 +43,8 @@ class ChangeNodePowerState(base.BaseAction):
'state': str, 'state': str,
}) })
The `resource_id` references a baremetal node id (list of available The `resource_id` references a ironic node id (list of available
ironic nodes is returned by this command: ``ironic node-list``). ironic node is returned by this command: ``ironic node-list``).
The `state` value should either be `on` or `off`. The `state` value should either be `on` or `off`.
""" """
@@ -59,14 +59,10 @@ class ChangeNodePowerState(base.BaseAction):
'type': 'string', 'type': 'string',
"minlength": 1 "minlength": 1
}, },
'resource_name': {
'type': 'string',
"minlength": 1
},
'state': { 'state': {
'type': 'string', 'type': 'string',
'enum': [metal_constants.PowerState.ON.value, 'enum': [NodeState.POWERON.value,
metal_constants.PowerState.OFF.value] NodeState.POWEROFF.value]
} }
}, },
'required': ['resource_id', 'state'], 'required': ['resource_id', 'state'],
@@ -86,10 +82,10 @@ class ChangeNodePowerState(base.BaseAction):
return self._node_manage_power(target_state) return self._node_manage_power(target_state)
def revert(self): def revert(self):
if self.state == metal_constants.PowerState.ON.value: if self.state == NodeState.POWERON.value:
target_state = metal_constants.PowerState.OFF.value target_state = NodeState.POWEROFF.value
elif self.state == metal_constants.PowerState.OFF.value: elif self.state == NodeState.POWEROFF.value:
target_state = metal_constants.PowerState.ON.value target_state = NodeState.POWERON.value
return self._node_manage_power(target_state) return self._node_manage_power(target_state)
def _node_manage_power(self, state, retry=60): def _node_manage_power(self, state, retry=60):
@@ -97,32 +93,30 @@ class ChangeNodePowerState(base.BaseAction):
raise exception.IllegalArgumentException( raise exception.IllegalArgumentException(
message=_("The target state is not defined")) message=_("The target state is not defined"))
metal_helper = metal_helper_factory.get_helper(self.osc) ironic_client = self.osc.ironic()
node = metal_helper.get_node(self.node_uuid) nova_client = self.osc.nova()
current_state = node.get_power_state() current_state = ironic_client.node.get(self.node_uuid).power_state
# power state: 'power on' or 'power off', if current node state
if state == current_state.value: # is the same as state, just return True
if state in current_state:
return True return True
if state == metal_constants.PowerState.OFF.value: if state == NodeState.POWEROFF.value:
compute_node = node.get_hypervisor_node().to_dict() node_info = ironic_client.node.get(self.node_uuid).to_dict()
compute_node_id = node_info['extra']['compute_node_id']
compute_node = nova_client.hypervisors.get(compute_node_id)
compute_node = compute_node.to_dict()
if (compute_node['running_vms'] == 0): if (compute_node['running_vms'] == 0):
node.set_power_state(state) ironic_client.node.set_power_state(
else: self.node_uuid, state)
LOG.warning(
"Compute node %s has %s running vms and will "
"NOT be shut off.",
compute_node["hypervisor_hostname"],
compute_node['running_vms'])
return False
else: else:
node.set_power_state(state) ironic_client.node.set_power_state(self.node_uuid, state)
node = metal_helper.get_node(self.node_uuid) ironic_node = ironic_client.node.get(self.node_uuid)
while node.get_power_state() == current_state and retry: while ironic_node.power_state == current_state and retry:
time.sleep(10) time.sleep(10)
retry -= 1 retry -= 1
node = metal_helper.get_node(self.node_uuid) ironic_node = ironic_client.node.get(self.node_uuid)
if retry > 0: if retry > 0:
return True return True
else: else:
@@ -136,4 +130,4 @@ class ChangeNodePowerState(base.BaseAction):
def get_description(self): def get_description(self):
"""Description of the action""" """Description of the action"""
return ("Compute node power on/off through Ironic or MaaS.") return ("Compute node power on/off through ironic.")

0
watcher/applier/default.py Normal file → Executable file
View File

View File

@@ -199,6 +199,5 @@ class TaskFlowNop(flow_task.Task):
We need at least two atoms to create a link. We need at least two atoms to create a link.
""" """
def execute(self): def execute(self):
pass pass

View File

@@ -15,15 +15,13 @@
# common/service.py. This allows the API service to run without monkey # common/service.py. This allows the API service to run without monkey
# patching under Apache (which uses its own concurrency model). Mixing # patching under Apache (which uses its own concurrency model). Mixing
# concurrency models can cause undefined behavior and potentially API timeouts. # concurrency models can cause undefined behavior and potentially API timeouts.
# NOTE(sean-k-mooney) while ^ is true, since that was written asyncio was added import eventlet
# to the code base in addition to apscheduler which provides native threads.
# As such we have a lot of technical debt to fix with regards to watchers eventlet.monkey_patch()
# concurrency model as we are mixing up to 3 models the same process.
# apscheduler does not technically support eventlet but it has mostly worked # Monkey patch the original current_thread to use the up-to-date _active
# until now, apscheduler is used to provide a job schedulers which mixes # global variable. See https://bugs.launchpad.net/bugs/1863021 and
# monkey patched and non monkey patched code in the same process. # https://github.com/eventlet/eventlet/issues/592
# That is problematic and can lead to errors on python 3.12+. import __original_module_threading as orig_threading # noqa
# The maas support added asyncio to the codebase which is unsafe to mix import threading # noqa
# with eventlets by default. orig_threading.current_thread.__globals__['_active'] = threading._active
from watcher import eventlet
eventlet.patch()

View File

@@ -14,7 +14,6 @@
import sys import sys
from oslo_upgradecheck import common_checks
from oslo_upgradecheck import upgradecheck from oslo_upgradecheck import upgradecheck
from watcher._i18n import _ from watcher._i18n import _
@@ -44,10 +43,6 @@ class Checks(upgradecheck.UpgradeCommands):
_upgrade_checks = ( _upgrade_checks = (
# Added in Train. # Added in Train.
(_('Minimum Nova API Version'), _minimum_nova_api_version), (_('Minimum Nova API Version'), _minimum_nova_api_version),
# Added in Wallaby.
(_("Policy File JSON to YAML Migration"),
(common_checks.check_policy_json, {'conf': CONF})),
) )

View File

@@ -17,7 +17,7 @@ import time
from oslo_log import log from oslo_log import log
from cinderclient import exceptions as cinder_exception from cinderclient import exceptions as cinder_exception
from cinderclient.v3.volumes import Volume from cinderclient.v2.volumes import Volume
from watcher._i18n import _ from watcher._i18n import _
from watcher.common import clients from watcher.common import clients
from watcher.common import exception from watcher.common import exception
@@ -153,7 +153,7 @@ class CinderHelper(object):
final_status = ('success', 'error') final_status = ('success', 'error')
while getattr(volume, 'migration_status') not in final_status: while getattr(volume, 'migration_status') not in final_status:
volume = self.get_volume(volume.id) volume = self.get_volume(volume.id)
LOG.debug('Waiting the migration of %s', volume) LOG.debug('Waiting the migration of {0}'.format(volume))
time.sleep(retry_interval) time.sleep(retry_interval)
if getattr(volume, 'migration_status') == 'error': if getattr(volume, 'migration_status') == 'error':
host_name = getattr(volume, 'os-vol-host-attr:host') host_name = getattr(volume, 'os-vol-host-attr:host')
@@ -230,7 +230,7 @@ class CinderHelper(object):
availability_zone=getattr(volume, 'availability_zone')) availability_zone=getattr(volume, 'availability_zone'))
while getattr(new_volume, 'status') != 'available' and retry: while getattr(new_volume, 'status') != 'available' and retry:
new_volume = cinder.volumes.get(new_volume.id) new_volume = cinder.volumes.get(new_volume.id)
LOG.debug('Waiting volume creation of %s', new_volume) LOG.debug('Waiting volume creation of {0}'.format(new_volume))
time.sleep(retry_interval) time.sleep(retry_interval)
retry -= 1 retry -= 1
LOG.debug("retry count: %s", retry) LOG.debug("retry count: %s", retry)

44
watcher/common/clients.py Normal file → Executable file
View File

@@ -25,13 +25,12 @@ from novaclient import api_versions as nova_api_versions
from novaclient import client as nvclient from novaclient import client as nvclient
from watcher.common import exception from watcher.common import exception
from watcher.common import utils
try: try:
from maas import client as maas_client from ceilometerclient import client as ceclient
HAS_CEILCLIENT = True
except ImportError: except ImportError:
maas_client = None HAS_CEILCLIENT = False
CONF = cfg.CONF CONF = cfg.CONF
@@ -71,10 +70,10 @@ class OpenStackClients(object):
self._glance = None self._glance = None
self._gnocchi = None self._gnocchi = None
self._cinder = None self._cinder = None
self._ceilometer = None
self._monasca = None self._monasca = None
self._neutron = None self._neutron = None
self._ironic = None self._ironic = None
self._maas = None
self._placement = None self._placement = None
def _get_keystone_session(self): def _get_keystone_session(self):
@@ -181,6 +180,24 @@ class OpenStackClients(object):
session=self.session) session=self.session)
return self._cinder return self._cinder
@exception.wrap_keystone_exception
def ceilometer(self):
if self._ceilometer:
return self._ceilometer
ceilometerclient_version = self._get_client_option('ceilometer',
'api_version')
ceilometer_endpoint_type = self._get_client_option('ceilometer',
'endpoint_type')
ceilometer_region_name = self._get_client_option('ceilometer',
'region_name')
self._ceilometer = ceclient.get_client(
ceilometerclient_version,
endpoint_type=ceilometer_endpoint_type,
region_name=ceilometer_region_name,
session=self.session)
return self._ceilometer
@exception.wrap_keystone_exception @exception.wrap_keystone_exception
def monasca(self): def monasca(self):
if self._monasca: if self._monasca:
@@ -248,23 +265,6 @@ class OpenStackClients(object):
session=self.session) session=self.session)
return self._ironic return self._ironic
def maas(self):
if self._maas:
return self._maas
if not maas_client:
raise exception.UnsupportedError(
"MAAS client unavailable. Please install python-libmaas.")
url = self._get_client_option('maas', 'url')
api_key = self._get_client_option('maas', 'api_key')
timeout = self._get_client_option('maas', 'timeout')
self._maas = utils.async_compat_call(
maas_client.connect,
url, apikey=api_key,
timeout=timeout)
return self._maas
@exception.wrap_keystone_exception @exception.wrap_keystone_exception
def placement(self): def placement(self):
if self._placement: if self._placement:

View File

@@ -11,15 +11,12 @@
# under the License. # under the License.
from oslo_context import context from oslo_context import context
from oslo_db.sqlalchemy import enginefacade
from oslo_log import log from oslo_log import log
from oslo_utils import timeutils from oslo_utils import timeutils
LOG = log.getLogger(__name__) LOG = log.getLogger(__name__)
@enginefacade.transaction_context_provider
class RequestContext(context.RequestContext): class RequestContext(context.RequestContext):
"""Extends security contexts from the OpenStack common library.""" """Extends security contexts from the OpenStack common library."""

View File

@@ -25,7 +25,6 @@ SHOULD include dedicated exception logging.
import functools import functools
import sys import sys
from http import HTTPStatus
from keystoneclient import exceptions as keystone_exceptions from keystoneclient import exceptions as keystone_exceptions
from oslo_config import cfg from oslo_config import cfg
from oslo_log import log from oslo_log import log
@@ -63,7 +62,7 @@ class WatcherException(Exception):
""" """
msg_fmt = _("An unknown exception occurred") msg_fmt = _("An unknown exception occurred")
code = HTTPStatus.INTERNAL_SERVER_ERROR code = 500
headers = {} headers = {}
safe = False safe = False
@@ -115,12 +114,12 @@ class UnsupportedError(WatcherException):
class NotAuthorized(WatcherException): class NotAuthorized(WatcherException):
msg_fmt = _("Not authorized") msg_fmt = _("Not authorized")
code = HTTPStatus.FORBIDDEN code = 403
class NotAcceptable(WatcherException): class NotAcceptable(WatcherException):
msg_fmt = _("Request not acceptable.") msg_fmt = _("Request not acceptable.")
code = HTTPStatus.NOT_ACCEPTABLE code = 406
class PolicyNotAuthorized(NotAuthorized): class PolicyNotAuthorized(NotAuthorized):
@@ -133,7 +132,7 @@ class OperationNotPermitted(NotAuthorized):
class Invalid(WatcherException, ValueError): class Invalid(WatcherException, ValueError):
msg_fmt = _("Unacceptable parameters") msg_fmt = _("Unacceptable parameters")
code = HTTPStatus.BAD_REQUEST code = 400
class ObjectNotFound(WatcherException): class ObjectNotFound(WatcherException):
@@ -142,22 +141,18 @@ class ObjectNotFound(WatcherException):
class Conflict(WatcherException): class Conflict(WatcherException):
msg_fmt = _('Conflict') msg_fmt = _('Conflict')
code = HTTPStatus.CONFLICT code = 409
class ResourceNotFound(ObjectNotFound): class ResourceNotFound(ObjectNotFound):
msg_fmt = _("The %(name)s resource %(id)s could not be found") msg_fmt = _("The %(name)s resource %(id)s could not be found")
code = HTTPStatus.NOT_FOUND code = 404
class InvalidParameter(Invalid): class InvalidParameter(Invalid):
msg_fmt = _("%(parameter)s has to be of type %(parameter_type)s") msg_fmt = _("%(parameter)s has to be of type %(parameter_type)s")
class MissingParameter(Invalid):
msg_fmt = _("%(parameter)s is required but missing. Check watcher.conf")
class InvalidIdentity(Invalid): class InvalidIdentity(Invalid):
msg_fmt = _("Expected a uuid or int but received %(identity)s") msg_fmt = _("Expected a uuid or int but received %(identity)s")

View File

@@ -72,8 +72,8 @@ class KeystoneHelper(object):
message=(_("Project not Found: %s") % name_or_id)) message=(_("Project not Found: %s") % name_or_id))
if len(projects) > 1: if len(projects) > 1:
raise exception.Invalid( raise exception.Invalid(
message=(_("Project name seems ambiguous: %s") % messsage=(_("Project name seems ambiguous: %s") %
name_or_id)) name_or_id))
return projects[0] return projects[0]
def get_domain(self, name_or_id): def get_domain(self, name_or_id):

View File

@@ -1,81 +0,0 @@
# Copyright 2023 Cloudbase Solutions
# 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.
import abc
from watcher.common import exception
from watcher.common.metal_helper import constants as metal_constants
class BaseMetalNode(abc.ABC):
hv_up_when_powered_off = False
def __init__(self, nova_node=None):
self._nova_node = nova_node
def get_hypervisor_node(self):
if not self._nova_node:
raise exception.Invalid(message="No associated hypervisor.")
return self._nova_node
def get_hypervisor_hostname(self):
return self.get_hypervisor_node().hypervisor_hostname
@abc.abstractmethod
def get_power_state(self):
# TODO(lpetrut): document the following methods
pass
@abc.abstractmethod
def get_id(self):
"""Return the node id provided by the bare metal service."""
pass
@abc.abstractmethod
def power_on(self):
pass
@abc.abstractmethod
def power_off(self):
pass
def set_power_state(self, state):
state = metal_constants.PowerState(state)
if state == metal_constants.PowerState.ON:
self.power_on()
elif state == metal_constants.PowerState.OFF:
self.power_off()
else:
raise exception.UnsupportedActionType(
"Cannot set power state: %s" % state)
class BaseMetalHelper(abc.ABC):
def __init__(self, osc):
self._osc = osc
@property
def nova_client(self):
if not getattr(self, "_nova_client", None):
self._nova_client = self._osc.nova()
return self._nova_client
@abc.abstractmethod
def list_compute_nodes(self):
pass
@abc.abstractmethod
def get_node(self, node_id):
pass

View File

@@ -1,23 +0,0 @@
# Copyright 2023 Cloudbase Solutions
# 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.
import enum
class PowerState(str, enum.Enum):
ON = "on"
OFF = "off"
UNKNOWN = "unknown"
ERROR = "error"

View File

@@ -1,33 +0,0 @@
# Copyright 2023 Cloudbase Solutions
# 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 oslo_config import cfg
from watcher.common import clients
from watcher.common.metal_helper import ironic
from watcher.common.metal_helper import maas
CONF = cfg.CONF
def get_helper(osc=None):
# TODO(lpetrut): consider caching this client.
if not osc:
osc = clients.OpenStackClients()
if CONF.maas_client.url:
return maas.MaasHelper(osc)
else:
return ironic.IronicHelper(osc)

View File

@@ -1,94 +0,0 @@
# Copyright 2023 Cloudbase Solutions
# 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 oslo_log import log
from watcher.common.metal_helper import base
from watcher.common.metal_helper import constants as metal_constants
LOG = log.getLogger(__name__)
POWER_STATES_MAP = {
'power on': metal_constants.PowerState.ON,
'power off': metal_constants.PowerState.OFF,
# For now, we only use ON/OFF states
'rebooting': metal_constants.PowerState.ON,
'soft power off': metal_constants.PowerState.OFF,
'soft reboot': metal_constants.PowerState.ON,
}
class IronicNode(base.BaseMetalNode):
hv_up_when_powered_off = True
def __init__(self, ironic_node, nova_node, ironic_client):
super().__init__(nova_node)
self._ironic_client = ironic_client
self._ironic_node = ironic_node
def get_power_state(self):
return POWER_STATES_MAP.get(self._ironic_node.power_state,
metal_constants.PowerState.UNKNOWN)
def get_id(self):
return self._ironic_node.uuid
def power_on(self):
self._ironic_client.node.set_power_state(self.get_id(), "on")
def power_off(self):
self._ironic_client.node.set_power_state(self.get_id(), "off")
class IronicHelper(base.BaseMetalHelper):
@property
def _client(self):
if not getattr(self, "_cached_client", None):
self._cached_client = self._osc.ironic()
return self._cached_client
def list_compute_nodes(self):
out_list = []
# TODO(lpetrut): consider using "detailed=True" instead of making
# an additional GET request per node
node_list = self._client.node.list()
for node in node_list:
node_info = self._client.node.get(node.uuid)
hypervisor_id = node_info.extra.get('compute_node_id', None)
if hypervisor_id is None:
LOG.warning('Cannot find compute_node_id in extra '
'of ironic node %s', node.uuid)
continue
hypervisor_node = self.nova_client.hypervisors.get(hypervisor_id)
if hypervisor_node is None:
LOG.warning('Cannot find hypervisor %s', hypervisor_id)
continue
out_node = IronicNode(node, hypervisor_node, self._client)
out_list.append(out_node)
return out_list
def get_node(self, node_id):
ironic_node = self._client.node.get(node_id)
compute_node_id = ironic_node.extra.get('compute_node_id')
if compute_node_id:
compute_node = self.nova_client.hypervisors.get(compute_node_id)
else:
compute_node = None
return IronicNode(ironic_node, compute_node, self._client)

View File

@@ -1,125 +0,0 @@
# Copyright 2023 Cloudbase Solutions
# 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 oslo_config import cfg
from oslo_log import log
from watcher.common import exception
from watcher.common.metal_helper import base
from watcher.common.metal_helper import constants as metal_constants
from watcher.common import utils
CONF = cfg.CONF
LOG = log.getLogger(__name__)
try:
from maas.client import enum as maas_enum
except ImportError:
maas_enum = None
class MaasNode(base.BaseMetalNode):
hv_up_when_powered_off = False
def __init__(self, maas_node, nova_node, maas_client):
super().__init__(nova_node)
self._maas_client = maas_client
self._maas_node = maas_node
def get_power_state(self):
maas_state = utils.async_compat_call(
self._maas_node.query_power_state,
timeout=CONF.maas_client.timeout)
# python-libmaas may not be available, so we'll avoid a global
# variable.
power_states_map = {
maas_enum.PowerState.ON: metal_constants.PowerState.ON,
maas_enum.PowerState.OFF: metal_constants.PowerState.OFF,
maas_enum.PowerState.ERROR: metal_constants.PowerState.ERROR,
maas_enum.PowerState.UNKNOWN: metal_constants.PowerState.UNKNOWN,
}
return power_states_map.get(maas_state,
metal_constants.PowerState.UNKNOWN)
def get_id(self):
return self._maas_node.system_id
def power_on(self):
LOG.info("Powering on MAAS node: %s %s",
self._maas_node.fqdn,
self._maas_node.system_id)
utils.async_compat_call(
self._maas_node.power_on,
timeout=CONF.maas_client.timeout)
def power_off(self):
LOG.info("Powering off MAAS node: %s %s",
self._maas_node.fqdn,
self._maas_node.system_id)
utils.async_compat_call(
self._maas_node.power_off,
timeout=CONF.maas_client.timeout)
class MaasHelper(base.BaseMetalHelper):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if not maas_enum:
raise exception.UnsupportedError(
"MAAS client unavailable. Please install python-libmaas.")
@property
def _client(self):
if not getattr(self, "_cached_client", None):
self._cached_client = self._osc.maas()
return self._cached_client
def list_compute_nodes(self):
out_list = []
node_list = utils.async_compat_call(
self._client.machines.list,
timeout=CONF.maas_client.timeout)
compute_nodes = self.nova_client.hypervisors.list()
compute_node_map = dict()
for compute_node in compute_nodes:
compute_node_map[compute_node.hypervisor_hostname] = compute_node
for node in node_list:
hypervisor_node = compute_node_map.get(node.fqdn)
if not hypervisor_node:
LOG.info('Cannot find hypervisor %s', node.fqdn)
continue
out_node = MaasNode(node, hypervisor_node, self._client)
out_list.append(out_node)
return out_list
def _get_compute_node_by_hostname(self, hostname):
compute_nodes = self.nova_client.hypervisors.search(
hostname, detailed=True)
for compute_node in compute_nodes:
if compute_node.hypervisor_hostname == hostname:
return compute_node
def get_node(self, node_id):
maas_node = utils.async_compat_call(
self._client.machines.get, node_id,
timeout=CONF.maas_client.timeout)
compute_node = self._get_compute_node_by_hostname(maas_node.fqdn)
return MaasNode(maas_node, compute_node, self._client)

View File

@@ -292,7 +292,9 @@ class NovaHelper(object):
'OS-EXT-STS:vm_state') != 'resized' \ 'OS-EXT-STS:vm_state') != 'resized' \
and retry: and retry:
instance = self.nova.servers.get(instance.id) instance = self.nova.servers.get(instance.id)
LOG.debug('Waiting the resize of %s to %s', instance, flavor_id) LOG.debug(
'Waiting the resize of {0} to {1}'.format(
instance, flavor_id))
time.sleep(1) time.sleep(1)
retry -= 1 retry -= 1
@@ -347,7 +349,8 @@ class NovaHelper(object):
if dest_hostname is None: if dest_hostname is None:
while (instance.status not in ['ACTIVE', 'ERROR'] and retry): while (instance.status not in ['ACTIVE', 'ERROR'] and retry):
instance = self.nova.servers.get(instance.id) instance = self.nova.servers.get(instance.id)
LOG.debug('Waiting the migration of %s', instance.id) LOG.debug(
'Waiting the migration of {0}'.format(instance.id))
time.sleep(1) time.sleep(1)
retry -= 1 retry -= 1
new_hostname = getattr(instance, 'OS-EXT-SRV-ATTR:host') new_hostname = getattr(instance, 'OS-EXT-SRV-ATTR:host')
@@ -368,9 +371,11 @@ class NovaHelper(object):
if not getattr(instance, 'OS-EXT-STS:task_state'): if not getattr(instance, 'OS-EXT-STS:task_state'):
LOG.debug("Instance task state: %s is null", instance_id) LOG.debug("Instance task state: %s is null", instance_id)
break break
LOG.debug('Waiting the migration of %s to %s', LOG.debug(
instance, 'Waiting the migration of {0} to {1}'.format(
getattr(instance, 'OS-EXT-SRV-ATTR:host')) instance,
getattr(instance,
'OS-EXT-SRV-ATTR:host')))
time.sleep(1) time.sleep(1)
retry -= 1 retry -= 1
@@ -720,7 +725,7 @@ class NovaHelper(object):
instance_id, old_volume.id, new_volume.id) instance_id, old_volume.id, new_volume.id)
while getattr(new_volume, 'status') != 'in-use' and retry: while getattr(new_volume, 'status') != 'in-use' and retry:
new_volume = self.cinder.volumes.get(new_volume.id) new_volume = self.cinder.volumes.get(new_volume.id)
LOG.debug('Waiting volume update to %s', new_volume) LOG.debug('Waiting volume update to {0}'.format(new_volume))
time.sleep(retry_interval) time.sleep(retry_interval)
retry -= 1 retry -= 1
LOG.debug("retry count: %s", retry) LOG.debug("retry count: %s", retry)

View File

@@ -11,7 +11,6 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
from http import HTTPStatus
from oslo_config import cfg from oslo_config import cfg
from oslo_log import log as logging from oslo_log import log as logging
@@ -54,7 +53,7 @@ class PlacementHelper(object):
if rp_name: if rp_name:
url += '?name=%s' % rp_name url += '?name=%s' % rp_name
resp = self.get(url) resp = self.get(url)
if resp.status_code == HTTPStatus.OK: if resp.status_code == 200:
json_resp = resp.json() json_resp = resp.json()
return json_resp['resource_providers'] return json_resp['resource_providers']
@@ -78,7 +77,7 @@ class PlacementHelper(object):
""" """
url = '/resource_providers/%s/inventories' % rp_uuid url = '/resource_providers/%s/inventories' % rp_uuid
resp = self.get(url) resp = self.get(url)
if resp.status_code == HTTPStatus.OK: if resp.status_code == 200:
json = resp.json() json = resp.json()
return json['inventories'] return json['inventories']
msg = ("Failed to get resource provider %(rp_uuid)s inventories. " msg = ("Failed to get resource provider %(rp_uuid)s inventories. "
@@ -98,7 +97,7 @@ class PlacementHelper(object):
""" """
resp = self.get("/resource_providers/%s/traits" % rp_uuid) resp = self.get("/resource_providers/%s/traits" % rp_uuid)
if resp.status_code == HTTPStatus.OK: if resp.status_code == 200:
json = resp.json() json = resp.json()
return json['traits'] return json['traits']
msg = ("Failed to get resource provider %(rp_uuid)s traits. " msg = ("Failed to get resource provider %(rp_uuid)s traits. "
@@ -119,7 +118,7 @@ class PlacementHelper(object):
""" """
url = '/allocations/%s' % consumer_uuid url = '/allocations/%s' % consumer_uuid
resp = self.get(url) resp = self.get(url)
if resp.status_code == HTTPStatus.OK: if resp.status_code == 200:
json = resp.json() json = resp.json()
return json['allocations'] return json['allocations']
msg = ("Failed to get allocations for consumer %(c_uuid). " msg = ("Failed to get allocations for consumer %(c_uuid). "
@@ -140,7 +139,7 @@ class PlacementHelper(object):
""" """
url = '/resource_providers/%s/usages' % rp_uuid url = '/resource_providers/%s/usages' % rp_uuid
resp = self.get(url) resp = self.get(url)
if resp.status_code == HTTPStatus.OK: if resp.status_code == 200:
json = resp.json() json = resp.json()
return json['usages'] return json['usages']
msg = ("Failed to get resource provider %(rp_uuid)s usages. " msg = ("Failed to get resource provider %(rp_uuid)s usages. "
@@ -165,7 +164,7 @@ class PlacementHelper(object):
""" """
url = "/allocation_candidates?%s" % resources url = "/allocation_candidates?%s" % resources
resp = self.get(url) resp = self.get(url)
if resp.status_code == HTTPStatus.OK: if resp.status_code == 200:
data = resp.json() data = resp.json()
return data['provider_summaries'] return data['provider_summaries']

Some files were not shown because too many files have changed in this diff Show More