Compare commits
67 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c2e16bfa96 | ||
|
|
13644429b7 | ||
|
|
b8cc506fbe | ||
|
|
c91f6479f0 | ||
|
|
92572c5dec | ||
|
|
a8f08065fd | ||
|
|
0745d904fc | ||
|
|
bc4a58d2d7 | ||
|
|
f14795d29f | ||
|
|
e0104074b6 | ||
|
|
2993dea376 | ||
|
|
17b6019ea9 | ||
|
|
5969e5b52a | ||
|
|
e55f3793b6 | ||
|
|
901c598dd7 | ||
|
|
e41a90d7ad | ||
|
|
051b4fcd06 | ||
|
|
cd045400ed | ||
|
|
2db668af30 | ||
|
|
39b1fcf07f | ||
|
|
94babf61da | ||
|
|
a5fba7ce28 | ||
|
|
24e01b6c98 | ||
|
|
4007f93aac | ||
|
|
77c9f88fc4 | ||
|
|
e9b7f067c5 | ||
|
|
f8aa02c4a7 | ||
|
|
3595108e49 | ||
|
|
d536ed248b | ||
|
|
71730c0eaf | ||
|
|
1b4c5dfc8b | ||
|
|
4179cfd036 | ||
|
|
49550db566 | ||
|
|
e0eba0ee7b | ||
|
|
165853ee2c | ||
|
|
0a7152fa55 | ||
|
|
6c29df11ca | ||
|
|
55bd0fd038 | ||
|
|
907cc2df16 | ||
|
|
8dcac1597b | ||
|
|
a3be1587e3 | ||
|
|
aa72f984e4 | ||
|
|
bcd2040025 | ||
|
|
f2c9dc9c32 | ||
|
|
6c94c235fc | ||
|
|
7ed45e3ef1 | ||
|
|
8722951022 | ||
|
|
568d4e831c | ||
|
|
deefc857ba | ||
|
|
d33736e7f0 | ||
|
|
1b1779cc49 | ||
|
|
d727bc3076 | ||
|
|
875b7e1ca3 | ||
|
|
c7f8755f9c | ||
|
|
0472715e0c | ||
|
|
2482e82548 | ||
|
|
e9c420467e | ||
|
|
2d5db7082b | ||
|
|
4a3a50435a | ||
|
|
05b57fee7a | ||
|
|
3729e39552 | ||
|
|
91911c8284 | ||
|
|
d7d56cbd79 | ||
|
|
d722b62b97 | ||
|
|
bf713ac7e1 | ||
|
|
51b3a15c90 | ||
|
|
74bc31e562 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -24,6 +24,7 @@ pip-log.txt
|
|||||||
.coverage*
|
.coverage*
|
||||||
.tox
|
.tox
|
||||||
nosetests.xml
|
nosetests.xml
|
||||||
|
.stestr/
|
||||||
.testrepository
|
.testrepository
|
||||||
.venv
|
.venv
|
||||||
.idea
|
.idea
|
||||||
|
|||||||
4
.stestr.conf
Normal file
4
.stestr.conf
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
[DEFAULT]
|
||||||
|
test_path=${OS_TEST_PATH:-./watcher/tests}
|
||||||
|
top_dir=./
|
||||||
|
|
||||||
39
.zuul.yaml
Normal file
39
.zuul.yaml
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
- project:
|
||||||
|
name: openstack/watcher
|
||||||
|
check:
|
||||||
|
jobs:
|
||||||
|
- watcher-tempest-multinode
|
||||||
|
- legacy-rally-dsvm-watcher-rally
|
||||||
|
|
||||||
|
- job:
|
||||||
|
name: watcher-tempest-base-multinode
|
||||||
|
parent: legacy-dsvm-base-multinode
|
||||||
|
run: playbooks/legacy/watcher-tempest-base-multinode/run.yaml
|
||||||
|
post-run: playbooks/legacy/watcher-tempest-base-multinode/post.yaml
|
||||||
|
timeout: 4200
|
||||||
|
required-projects:
|
||||||
|
- openstack-infra/devstack-gate
|
||||||
|
- openstack/python-openstackclient
|
||||||
|
- openstack/python-watcherclient
|
||||||
|
- openstack/watcher
|
||||||
|
- openstack/watcher-tempest-plugin
|
||||||
|
nodeset: legacy-ubuntu-xenial-2-node
|
||||||
|
|
||||||
|
- job:
|
||||||
|
name: watcher-tempest-multinode
|
||||||
|
parent: watcher-tempest-base-multinode
|
||||||
|
voting: false
|
||||||
|
|
||||||
|
- job:
|
||||||
|
# This job is used by python-watcherclient repo
|
||||||
|
name: watcherclient-tempest-functional
|
||||||
|
parent: legacy-dsvm-base
|
||||||
|
run: playbooks/legacy/watcherclient-tempest-functional/run.yaml
|
||||||
|
post-run: playbooks/legacy/watcherclient-tempest-functional/post.yaml
|
||||||
|
timeout: 4200
|
||||||
|
required-projects:
|
||||||
|
- openstack-dev/devstack
|
||||||
|
- openstack-infra/devstack-gate
|
||||||
|
- openstack/python-openstackclient
|
||||||
|
- openstack/python-watcherclient
|
||||||
|
- openstack/watcher
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
"watcher_object.name": "TerseActionPlanPayload",
|
"watcher_object.name": "TerseActionPlanPayload",
|
||||||
"watcher_object.data": {
|
"watcher_object.data": {
|
||||||
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
|
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
|
||||||
"global_efficacy": {},
|
"global_efficacy": [],
|
||||||
"created_at": "2016-10-18T09:52:05Z",
|
"created_at": "2016-10-18T09:52:05Z",
|
||||||
"updated_at": null,
|
"updated_at": null,
|
||||||
"state": "CANCELLING",
|
"state": "CANCELLING",
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
"watcher_object.name": "TerseActionPlanPayload",
|
"watcher_object.name": "TerseActionPlanPayload",
|
||||||
"watcher_object.data": {
|
"watcher_object.data": {
|
||||||
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
|
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
|
||||||
"global_efficacy": {},
|
"global_efficacy": [],
|
||||||
"created_at": "2016-10-18T09:52:05Z",
|
"created_at": "2016-10-18T09:52:05Z",
|
||||||
"updated_at": null,
|
"updated_at": null,
|
||||||
"state": "CANCELLING",
|
"state": "CANCELLING",
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
"watcher_object.name": "TerseActionPlanPayload",
|
"watcher_object.name": "TerseActionPlanPayload",
|
||||||
"watcher_object.data": {
|
"watcher_object.data": {
|
||||||
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
|
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
|
||||||
"global_efficacy": {},
|
"global_efficacy": [],
|
||||||
"created_at": "2016-10-18T09:52:05Z",
|
"created_at": "2016-10-18T09:52:05Z",
|
||||||
"updated_at": null,
|
"updated_at": null,
|
||||||
"state": "CANCELLING",
|
"state": "CANCELLING",
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
"watcher_object.name": "TerseActionPlanPayload",
|
"watcher_object.name": "TerseActionPlanPayload",
|
||||||
"watcher_object.data": {
|
"watcher_object.data": {
|
||||||
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
|
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
|
||||||
"global_efficacy": {},
|
"global_efficacy": [],
|
||||||
"created_at": "2016-10-18T09:52:05Z",
|
"created_at": "2016-10-18T09:52:05Z",
|
||||||
"updated_at": null,
|
"updated_at": null,
|
||||||
"state": "ONGOING",
|
"state": "ONGOING",
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
"watcher_object.name": "TerseActionPlanPayload",
|
"watcher_object.name": "TerseActionPlanPayload",
|
||||||
"watcher_object.data": {
|
"watcher_object.data": {
|
||||||
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
|
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
|
||||||
"global_efficacy": {},
|
"global_efficacy":[],
|
||||||
"created_at": "2016-10-18T09:52:05Z",
|
"created_at": "2016-10-18T09:52:05Z",
|
||||||
"updated_at": null,
|
"updated_at": null,
|
||||||
"state": "ONGOING",
|
"state": "ONGOING",
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
"watcher_object.name": "TerseActionPlanPayload",
|
"watcher_object.name": "TerseActionPlanPayload",
|
||||||
"watcher_object.data": {
|
"watcher_object.data": {
|
||||||
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
|
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
|
||||||
"global_efficacy": {},
|
"global_efficacy": [],
|
||||||
"created_at": "2016-10-18T09:52:05Z",
|
"created_at": "2016-10-18T09:52:05Z",
|
||||||
"updated_at": null,
|
"updated_at": null,
|
||||||
"state": "ONGOING",
|
"state": "ONGOING",
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
|
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
|
||||||
"fault": null,
|
"fault": null,
|
||||||
"state": "CANCELLED",
|
"state": "CANCELLED",
|
||||||
"global_efficacy": {},
|
"global_efficacy": [],
|
||||||
"strategy_uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
|
"strategy_uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
|
||||||
"strategy": {
|
"strategy": {
|
||||||
"watcher_object.namespace": "watcher",
|
"watcher_object.namespace": "watcher",
|
||||||
|
|||||||
@@ -57,7 +57,7 @@
|
|||||||
"state": "SUCCEEDED"
|
"state": "SUCCEEDED"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"global_efficacy": {},
|
"global_efficacy": [],
|
||||||
"state": "CANCELLING"
|
"state": "CANCELLING"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
|
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
|
||||||
"fault": null,
|
"fault": null,
|
||||||
"state": "CANCELLING",
|
"state": "CANCELLING",
|
||||||
"global_efficacy": {},
|
"global_efficacy": [],
|
||||||
"strategy_uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
|
"strategy_uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
|
||||||
"strategy": {
|
"strategy": {
|
||||||
"watcher_object.namespace": "watcher",
|
"watcher_object.namespace": "watcher",
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
"audit": {
|
"audit": {
|
||||||
"watcher_object.version": "1.0",
|
"watcher_object.version": "1.0",
|
||||||
"watcher_object.data": {
|
"watcher_object.data": {
|
||||||
|
"name": "my_audit",
|
||||||
"audit_type": "ONESHOT",
|
"audit_type": "ONESHOT",
|
||||||
"scope": [],
|
"scope": [],
|
||||||
"uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
"uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
"audit_uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
"audit_uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
||||||
"audit": {
|
"audit": {
|
||||||
"watcher_object.data": {
|
"watcher_object.data": {
|
||||||
|
"name": "my_audit",
|
||||||
"uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
"uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
||||||
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
||||||
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
"watcher_object.data": {
|
"watcher_object.data": {
|
||||||
"created_at": "2016-10-18T09:52:05Z",
|
"created_at": "2016-10-18T09:52:05Z",
|
||||||
"deleted_at": null,
|
"deleted_at": null,
|
||||||
|
"name": "my_audit",
|
||||||
"uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
"uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
||||||
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
||||||
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
||||||
@@ -29,7 +30,7 @@
|
|||||||
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
|
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
|
||||||
"fault": null,
|
"fault": null,
|
||||||
"state": "ONGOING",
|
"state": "ONGOING",
|
||||||
"global_efficacy": {},
|
"global_efficacy": [],
|
||||||
"strategy_uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
|
"strategy_uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
|
||||||
"strategy": {
|
"strategy": {
|
||||||
"watcher_object.namespace": "watcher",
|
"watcher_object.namespace": "watcher",
|
||||||
|
|||||||
@@ -45,6 +45,7 @@
|
|||||||
"watcher_object.name": "TerseAuditPayload",
|
"watcher_object.name": "TerseAuditPayload",
|
||||||
"watcher_object.data": {
|
"watcher_object.data": {
|
||||||
"parameters": {},
|
"parameters": {},
|
||||||
|
"name": "my_audit",
|
||||||
"uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
"uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
||||||
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
||||||
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
||||||
@@ -57,7 +58,7 @@
|
|||||||
"state": "PENDING"
|
"state": "PENDING"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"global_efficacy": {},
|
"global_efficacy": [],
|
||||||
"state": "ONGOING"
|
"state": "ONGOING"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
"watcher_object.data": {
|
"watcher_object.data": {
|
||||||
"created_at": "2016-10-18T09:52:05Z",
|
"created_at": "2016-10-18T09:52:05Z",
|
||||||
"deleted_at": null,
|
"deleted_at": null,
|
||||||
|
"name": "my_audit",
|
||||||
"uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
"uuid": "10a47dd1-4874-4298-91cf-eff046dbdb8d",
|
||||||
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
"goal_uuid": "bc830f84-8ae3-4fc6-8bc6-e3dd15e8b49a",
|
||||||
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
||||||
@@ -29,7 +30,7 @@
|
|||||||
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
|
"uuid": "76be87bd-3422-43f9-93a0-e85a577e3061",
|
||||||
"fault": null,
|
"fault": null,
|
||||||
"state": "ONGOING",
|
"state": "ONGOING",
|
||||||
"global_efficacy": {},
|
"global_efficacy": [],
|
||||||
"strategy_uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
|
"strategy_uuid": "cb3d0b58-4415-4d90-b75b-1e96878730e3",
|
||||||
"strategy": {
|
"strategy": {
|
||||||
"watcher_object.namespace": "watcher",
|
"watcher_object.namespace": "watcher",
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
"audit": {
|
"audit": {
|
||||||
"watcher_object.version": "1.0",
|
"watcher_object.version": "1.0",
|
||||||
"watcher_object.data": {
|
"watcher_object.data": {
|
||||||
|
"name": "my_audit",
|
||||||
"audit_type": "ONESHOT",
|
"audit_type": "ONESHOT",
|
||||||
"scope": [],
|
"scope": [],
|
||||||
"created_at": "2016-10-18T09:52:05Z",
|
"created_at": "2016-10-18T09:52:05Z",
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
"priority": "INFO",
|
"priority": "INFO",
|
||||||
"payload": {
|
"payload": {
|
||||||
"watcher_object.data": {
|
"watcher_object.data": {
|
||||||
|
"name": "my_audit",
|
||||||
"audit_type": "ONESHOT",
|
"audit_type": "ONESHOT",
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"para2": "hello",
|
"para2": "hello",
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
"priority": "INFO",
|
"priority": "INFO",
|
||||||
"payload": {
|
"payload": {
|
||||||
"watcher_object.data": {
|
"watcher_object.data": {
|
||||||
|
"name": "my_audit",
|
||||||
"audit_type": "ONESHOT",
|
"audit_type": "ONESHOT",
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"para2": "hello",
|
"para2": "hello",
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
"priority": "INFO",
|
"priority": "INFO",
|
||||||
"payload": {
|
"payload": {
|
||||||
"watcher_object.data": {
|
"watcher_object.data": {
|
||||||
|
"name": "my_audit",
|
||||||
"audit_type": "ONESHOT",
|
"audit_type": "ONESHOT",
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"para2": "hello",
|
"para2": "hello",
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
"priority": "ERROR",
|
"priority": "ERROR",
|
||||||
"payload": {
|
"payload": {
|
||||||
"watcher_object.data": {
|
"watcher_object.data": {
|
||||||
|
"name": "my_audit",
|
||||||
"audit_type": "ONESHOT",
|
"audit_type": "ONESHOT",
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"para2": "hello",
|
"para2": "hello",
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
"priority": "INFO",
|
"priority": "INFO",
|
||||||
"payload": {
|
"payload": {
|
||||||
"watcher_object.data": {
|
"watcher_object.data": {
|
||||||
|
"name": "my_audit",
|
||||||
"audit_type": "ONESHOT",
|
"audit_type": "ONESHOT",
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"para2": "hello",
|
"para2": "hello",
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
"priority": "INFO",
|
"priority": "INFO",
|
||||||
"payload": {
|
"payload": {
|
||||||
"watcher_object.data": {
|
"watcher_object.data": {
|
||||||
|
"name": "my_audit",
|
||||||
"audit_type": "ONESHOT",
|
"audit_type": "ONESHOT",
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"para2": "hello",
|
"para2": "hello",
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
"priority": "ERROR",
|
"priority": "ERROR",
|
||||||
"payload": {
|
"payload": {
|
||||||
"watcher_object.data": {
|
"watcher_object.data": {
|
||||||
|
"name": "my_audit",
|
||||||
"audit_type": "ONESHOT",
|
"audit_type": "ONESHOT",
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"para2": "hello",
|
"para2": "hello",
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
"priority": "INFO",
|
"priority": "INFO",
|
||||||
"payload": {
|
"payload": {
|
||||||
"watcher_object.data": {
|
"watcher_object.data": {
|
||||||
|
"name": "my_audit",
|
||||||
"audit_type": "ONESHOT",
|
"audit_type": "ONESHOT",
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"para2": "hello",
|
"para2": "hello",
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
"payload": {
|
"payload": {
|
||||||
"watcher_object.name": "AuditUpdatePayload",
|
"watcher_object.name": "AuditUpdatePayload",
|
||||||
"watcher_object.data": {
|
"watcher_object.data": {
|
||||||
|
"name": "my_audit",
|
||||||
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
"strategy_uuid": "75234dfe-87e3-4f11-a0e0-3c3305d86a39",
|
||||||
"strategy": {
|
"strategy": {
|
||||||
"watcher_object.name": "StrategyPayload",
|
"watcher_object.name": "StrategyPayload",
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ Here is single Dockerfile snippet you can use to run your Docker container:
|
|||||||
MAINTAINER David TARDIVEL <david.tardivel@b-com.com>
|
MAINTAINER David TARDIVEL <david.tardivel@b-com.com>
|
||||||
|
|
||||||
RUN apt-get update
|
RUN apt-get update
|
||||||
RUN apt-get dist-upgrade -y
|
RUN apt-get dist-upgrade
|
||||||
RUN apt-get install vim net-tools
|
RUN apt-get install vim net-tools
|
||||||
RUN apt-get install experimental watcher-api
|
RUN apt-get install experimental watcher-api
|
||||||
|
|
||||||
|
|||||||
@@ -86,3 +86,15 @@ Actions
|
|||||||
|
|
||||||
.. autotype:: watcher.api.controllers.v1.action.Action
|
.. autotype:: watcher.api.controllers.v1.action.Action
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
Scoring Engine
|
||||||
|
==============
|
||||||
|
|
||||||
|
.. rest-controller:: watcher.api.controllers.v1.scoring_engine:ScoringEngineController
|
||||||
|
:webprefix: /v1/scoring_engine
|
||||||
|
|
||||||
|
.. autotype:: watcher.api.controllers.v1.scoring_engine.ScoringEngineCollection
|
||||||
|
:members:
|
||||||
|
|
||||||
|
.. autotype:: watcher.api.controllers.v1.scoring_engine.ScoringEngine
|
||||||
|
:members:
|
||||||
|
|||||||
@@ -24,8 +24,8 @@ signed OpenStack's contributor's agreement.
|
|||||||
|
|
||||||
.. seealso::
|
.. seealso::
|
||||||
|
|
||||||
* http://docs.openstack.org/infra/manual/developers.html
|
* https://docs.openstack.org/infra/manual/developers.html
|
||||||
* http://wiki.openstack.org/CLA
|
* https://wiki.openstack.org/CLA
|
||||||
|
|
||||||
LaunchPad Project
|
LaunchPad Project
|
||||||
-----------------
|
-----------------
|
||||||
@@ -37,22 +37,22 @@ notifications of important events.
|
|||||||
|
|
||||||
.. seealso::
|
.. seealso::
|
||||||
|
|
||||||
* http://launchpad.net
|
* https://launchpad.net
|
||||||
* http://launchpad.net/watcher
|
* https://launchpad.net/watcher
|
||||||
* http://launchpad.net/~openstack
|
* https://launchpad.net/~openstack
|
||||||
|
|
||||||
|
|
||||||
Project Hosting Details
|
Project Hosting Details
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
Bug tracker
|
Bug tracker
|
||||||
http://launchpad.net/watcher
|
https://launchpad.net/watcher
|
||||||
|
|
||||||
Mailing list (prefix subjects with ``[watcher]`` for faster responses)
|
Mailing list (prefix subjects with ``[watcher]`` for faster responses)
|
||||||
http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev
|
https://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev
|
||||||
|
|
||||||
Wiki
|
Wiki
|
||||||
http://wiki.openstack.org/Watcher
|
https://wiki.openstack.org/Watcher
|
||||||
|
|
||||||
Code Hosting
|
Code Hosting
|
||||||
https://git.openstack.org/cgit/openstack/watcher
|
https://git.openstack.org/cgit/openstack/watcher
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ Detailed DevStack Instructions
|
|||||||
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 14.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::
|
||||||
|
|||||||
@@ -69,8 +69,8 @@ itself.
|
|||||||
|
|
||||||
These dependencies can be installed from PyPi_ using the Python tool pip_.
|
These dependencies can be installed from PyPi_ using the Python tool pip_.
|
||||||
|
|
||||||
.. _PyPi: http://pypi.python.org/
|
.. _PyPi: https://pypi.python.org/
|
||||||
.. _pip: http://pypi.python.org/pypi/pip
|
.. _pip: https://pypi.python.org/pypi/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
|
||||||
@@ -125,7 +125,7 @@ You can re-activate this virtualenv for your current shell using:
|
|||||||
|
|
||||||
For more information on virtual environments, see virtualenv_.
|
For more information on virtual environments, see virtualenv_.
|
||||||
|
|
||||||
.. _virtualenv: http://www.virtualenv.org/
|
.. _virtualenv: https://www.virtualenv.org/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ In order to create a new cluster data model collector, you have to:
|
|||||||
- Implement its :py:meth:`~.BaseClusterDataModelCollector.execute` abstract
|
- Implement its :py:meth:`~.BaseClusterDataModelCollector.execute` abstract
|
||||||
method to return your entire cluster data model that this method should
|
method to return your entire cluster data model that this method should
|
||||||
build.
|
build.
|
||||||
|
- Implement its :py:meth:`~.BaseClusterDataModelCollector.audit_scope_handler`
|
||||||
|
abstract property to return your audit scope handler.
|
||||||
- Implement its :py:meth:`~.Goal.notification_endpoints` abstract property to
|
- Implement its :py:meth:`~.Goal.notification_endpoints` abstract property to
|
||||||
return the list of all the :py:class:`~.base.NotificationEndpoint` instances
|
return the list of all the :py:class:`~.base.NotificationEndpoint` instances
|
||||||
that will be responsible for handling incoming notifications in order to
|
that will be responsible for handling incoming notifications in order to
|
||||||
@@ -57,6 +59,10 @@ Here is an example showing how you can write a plugin called
|
|||||||
# Do something here...
|
# Do something here...
|
||||||
return model
|
return model
|
||||||
|
|
||||||
|
@property
|
||||||
|
def audit_scope_handler(self):
|
||||||
|
return None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def notification_endpoints(self):
|
def notification_endpoints(self):
|
||||||
return []
|
return []
|
||||||
@@ -135,6 +141,10 @@ class method as followed:
|
|||||||
# Do something here...
|
# Do something here...
|
||||||
return model
|
return model
|
||||||
|
|
||||||
|
@property
|
||||||
|
def audit_scope_handler(self):
|
||||||
|
return None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def notification_endpoints(self):
|
def notification_endpoints(self):
|
||||||
return []
|
return []
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ table(action_plans) {
|
|||||||
foreign_key("strategy_id : Integer")
|
foreign_key("strategy_id : Integer")
|
||||||
uuid : String[36]
|
uuid : String[36]
|
||||||
state : String[20], nullable
|
state : String[20], nullable
|
||||||
global_efficacy : JSONEncodedDict, nullable
|
global_efficacy : JSONEncodedList, nullable
|
||||||
|
|
||||||
created_at : DateTime
|
created_at : DateTime
|
||||||
updated_at : DateTime
|
updated_at : DateTime
|
||||||
|
|||||||
15
playbooks/legacy/watcher-tempest-base-multinode/post.yaml
Normal file
15
playbooks/legacy/watcher-tempest-base-multinode/post.yaml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
- hosts: primary
|
||||||
|
tasks:
|
||||||
|
|
||||||
|
- name: Copy files from {{ ansible_user_dir }}/workspace/ on node
|
||||||
|
synchronize:
|
||||||
|
src: '{{ ansible_user_dir }}/workspace/'
|
||||||
|
dest: '{{ zuul.executor.log_root }}'
|
||||||
|
mode: pull
|
||||||
|
copy_links: true
|
||||||
|
verify_host: true
|
||||||
|
rsync_opts:
|
||||||
|
- --include=/logs/**
|
||||||
|
- --include=*/
|
||||||
|
- --exclude=*
|
||||||
|
- --prune-empty-dirs
|
||||||
67
playbooks/legacy/watcher-tempest-base-multinode/run.yaml
Normal file
67
playbooks/legacy/watcher-tempest-base-multinode/run.yaml
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
- hosts: primary
|
||||||
|
name: Legacy Watcher tempest base multinode
|
||||||
|
tasks:
|
||||||
|
|
||||||
|
- name: Ensure legacy workspace directory
|
||||||
|
file:
|
||||||
|
path: '{{ ansible_user_dir }}/workspace'
|
||||||
|
state: directory
|
||||||
|
|
||||||
|
- shell:
|
||||||
|
cmd: |
|
||||||
|
set -e
|
||||||
|
set -x
|
||||||
|
cat > clonemap.yaml << EOF
|
||||||
|
clonemap:
|
||||||
|
- name: openstack-infra/devstack-gate
|
||||||
|
dest: devstack-gate
|
||||||
|
EOF
|
||||||
|
/usr/zuul-env/bin/zuul-cloner -m clonemap.yaml --cache-dir /opt/git \
|
||||||
|
git://git.openstack.org \
|
||||||
|
openstack-infra/devstack-gate
|
||||||
|
executable: /bin/bash
|
||||||
|
chdir: '{{ ansible_user_dir }}/workspace'
|
||||||
|
environment: '{{ zuul | zuul_legacy_vars }}'
|
||||||
|
|
||||||
|
- shell:
|
||||||
|
cmd: |
|
||||||
|
set -e
|
||||||
|
set -x
|
||||||
|
cat << 'EOF' >>"/tmp/dg-local.conf"
|
||||||
|
[[local|localrc]]
|
||||||
|
TEMPEST_PLUGINS='/opt/stack/new/watcher-tempest-plugin'
|
||||||
|
enable_plugin ceilometer git://git.openstack.org/openstack/ceilometer
|
||||||
|
# Enable watcher devstack plugin.
|
||||||
|
enable_plugin watcher git://git.openstack.org/openstack/watcher
|
||||||
|
|
||||||
|
EOF
|
||||||
|
executable: /bin/bash
|
||||||
|
chdir: '{{ ansible_user_dir }}/workspace'
|
||||||
|
environment: '{{ zuul | zuul_legacy_vars }}'
|
||||||
|
|
||||||
|
- shell:
|
||||||
|
cmd: |
|
||||||
|
set -e
|
||||||
|
set -x
|
||||||
|
|
||||||
|
export DEVSTACK_SUBNODE_CONFIG=" "
|
||||||
|
export PYTHONUNBUFFERED=true
|
||||||
|
export DEVSTACK_GATE_TEMPEST=1
|
||||||
|
export DEVSTACK_GATE_NEUTRON=1
|
||||||
|
export DEVSTACK_GATE_TOPOLOGY="multinode"
|
||||||
|
export PROJECTS="openstack/watcher $PROJECTS"
|
||||||
|
export PROJECTS="openstack/python-watcherclient $PROJECTS"
|
||||||
|
export PROJECTS="openstack/watcher-tempest-plugin $PROJECTS"
|
||||||
|
|
||||||
|
export DEVSTACK_GATE_TEMPEST_REGEX="watcher_tempest_plugin"
|
||||||
|
|
||||||
|
export BRANCH_OVERRIDE=default
|
||||||
|
if [ "$BRANCH_OVERRIDE" != "default" ] ; then
|
||||||
|
export OVERRIDE_ZUUL_BRANCH=$BRANCH_OVERRIDE
|
||||||
|
fi
|
||||||
|
|
||||||
|
cp devstack-gate/devstack-vm-gate-wrap.sh ./safe-devstack-vm-gate-wrap.sh
|
||||||
|
./safe-devstack-vm-gate-wrap.sh
|
||||||
|
executable: /bin/bash
|
||||||
|
chdir: '{{ ansible_user_dir }}/workspace'
|
||||||
|
environment: '{{ zuul | zuul_legacy_vars }}'
|
||||||
80
playbooks/legacy/watcherclient-tempest-functional/post.yaml
Normal file
80
playbooks/legacy/watcherclient-tempest-functional/post.yaml
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
- hosts: primary
|
||||||
|
tasks:
|
||||||
|
|
||||||
|
- name: Copy files from {{ ansible_user_dir }}/workspace/ on node
|
||||||
|
synchronize:
|
||||||
|
src: '{{ ansible_user_dir }}/workspace/'
|
||||||
|
dest: '{{ zuul.executor.log_root }}'
|
||||||
|
mode: pull
|
||||||
|
copy_links: true
|
||||||
|
verify_host: true
|
||||||
|
rsync_opts:
|
||||||
|
- --include=**/*nose_results.html
|
||||||
|
- --include=*/
|
||||||
|
- --exclude=*
|
||||||
|
- --prune-empty-dirs
|
||||||
|
|
||||||
|
- name: Copy files from {{ ansible_user_dir }}/workspace/ on node
|
||||||
|
synchronize:
|
||||||
|
src: '{{ ansible_user_dir }}/workspace/'
|
||||||
|
dest: '{{ zuul.executor.log_root }}'
|
||||||
|
mode: pull
|
||||||
|
copy_links: true
|
||||||
|
verify_host: true
|
||||||
|
rsync_opts:
|
||||||
|
- --include=**/*testr_results.html.gz
|
||||||
|
- --include=*/
|
||||||
|
- --exclude=*
|
||||||
|
- --prune-empty-dirs
|
||||||
|
|
||||||
|
- name: Copy files from {{ ansible_user_dir }}/workspace/ on node
|
||||||
|
synchronize:
|
||||||
|
src: '{{ ansible_user_dir }}/workspace/'
|
||||||
|
dest: '{{ zuul.executor.log_root }}'
|
||||||
|
mode: pull
|
||||||
|
copy_links: true
|
||||||
|
verify_host: true
|
||||||
|
rsync_opts:
|
||||||
|
- --include=/.testrepository/tmp*
|
||||||
|
- --include=*/
|
||||||
|
- --exclude=*
|
||||||
|
- --prune-empty-dirs
|
||||||
|
|
||||||
|
- name: Copy files from {{ ansible_user_dir }}/workspace/ on node
|
||||||
|
synchronize:
|
||||||
|
src: '{{ ansible_user_dir }}/workspace/'
|
||||||
|
dest: '{{ zuul.executor.log_root }}'
|
||||||
|
mode: pull
|
||||||
|
copy_links: true
|
||||||
|
verify_host: true
|
||||||
|
rsync_opts:
|
||||||
|
- --include=**/*testrepository.subunit.gz
|
||||||
|
- --include=*/
|
||||||
|
- --exclude=*
|
||||||
|
- --prune-empty-dirs
|
||||||
|
|
||||||
|
- name: Copy files from {{ ansible_user_dir }}/workspace/ on node
|
||||||
|
synchronize:
|
||||||
|
src: '{{ ansible_user_dir }}/workspace/'
|
||||||
|
dest: '{{ zuul.executor.log_root }}/tox'
|
||||||
|
mode: pull
|
||||||
|
copy_links: true
|
||||||
|
verify_host: true
|
||||||
|
rsync_opts:
|
||||||
|
- --include=/.tox/*/log/*
|
||||||
|
- --include=*/
|
||||||
|
- --exclude=*
|
||||||
|
- --prune-empty-dirs
|
||||||
|
|
||||||
|
- name: Copy files from {{ ansible_user_dir }}/workspace/ on node
|
||||||
|
synchronize:
|
||||||
|
src: '{{ ansible_user_dir }}/workspace/'
|
||||||
|
dest: '{{ zuul.executor.log_root }}'
|
||||||
|
mode: pull
|
||||||
|
copy_links: true
|
||||||
|
verify_host: true
|
||||||
|
rsync_opts:
|
||||||
|
- --include=/logs/**
|
||||||
|
- --include=*/
|
||||||
|
- --exclude=*
|
||||||
|
- --prune-empty-dirs
|
||||||
64
playbooks/legacy/watcherclient-tempest-functional/run.yaml
Normal file
64
playbooks/legacy/watcherclient-tempest-functional/run.yaml
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
- hosts: all
|
||||||
|
name: Legacy watcherclient-dsvm-functional
|
||||||
|
tasks:
|
||||||
|
|
||||||
|
- name: Ensure legacy workspace directory
|
||||||
|
file:
|
||||||
|
path: '{{ ansible_user_dir }}/workspace'
|
||||||
|
state: directory
|
||||||
|
|
||||||
|
- shell:
|
||||||
|
cmd: |
|
||||||
|
set -e
|
||||||
|
set -x
|
||||||
|
cat > clonemap.yaml << EOF
|
||||||
|
clonemap:
|
||||||
|
- name: openstack-infra/devstack-gate
|
||||||
|
dest: devstack-gate
|
||||||
|
EOF
|
||||||
|
/usr/zuul-env/bin/zuul-cloner -m clonemap.yaml --cache-dir /opt/git \
|
||||||
|
git://git.openstack.org \
|
||||||
|
openstack-infra/devstack-gate
|
||||||
|
executable: /bin/bash
|
||||||
|
chdir: '{{ ansible_user_dir }}/workspace'
|
||||||
|
environment: '{{ zuul | zuul_legacy_vars }}'
|
||||||
|
|
||||||
|
- shell:
|
||||||
|
cmd: |
|
||||||
|
set -e
|
||||||
|
set -x
|
||||||
|
cat << 'EOF' >>"/tmp/dg-local.conf"
|
||||||
|
[[local|localrc]]
|
||||||
|
enable_plugin watcher git://git.openstack.org/openstack/watcher
|
||||||
|
|
||||||
|
EOF
|
||||||
|
executable: /bin/bash
|
||||||
|
chdir: '{{ ansible_user_dir }}/workspace'
|
||||||
|
environment: '{{ zuul | zuul_legacy_vars }}'
|
||||||
|
|
||||||
|
- shell:
|
||||||
|
cmd: |
|
||||||
|
set -e
|
||||||
|
set -x
|
||||||
|
ENABLED_SERVICES=tempest
|
||||||
|
ENABLED_SERVICES+=,watcher-api,watcher-decision-engine,watcher-applier
|
||||||
|
export ENABLED_SERVICES
|
||||||
|
|
||||||
|
export PYTHONUNBUFFERED=true
|
||||||
|
export BRANCH_OVERRIDE=default
|
||||||
|
export PROJECTS="openstack/watcher $PROJECTS"
|
||||||
|
export DEVSTACK_PROJECT_FROM_GIT=python-watcherclient
|
||||||
|
if [ "$BRANCH_OVERRIDE" != "default" ] ; then
|
||||||
|
export OVERRIDE_ZUUL_BRANCH=$BRANCH_OVERRIDE
|
||||||
|
fi
|
||||||
|
function post_test_hook {
|
||||||
|
# Configure and run functional tests
|
||||||
|
$BASE/new/python-watcherclient/watcherclient/tests/functional/hooks/post_test_hook.sh
|
||||||
|
}
|
||||||
|
export -f post_test_hook
|
||||||
|
|
||||||
|
cp devstack-gate/devstack-vm-gate-wrap.sh ./safe-devstack-vm-gate-wrap.sh
|
||||||
|
./safe-devstack-vm-gate-wrap.sh
|
||||||
|
executable: /bin/bash
|
||||||
|
chdir: '{{ ansible_user_dir }}/workspace'
|
||||||
|
environment: '{{ zuul | zuul_legacy_vars }}'
|
||||||
@@ -29,14 +29,14 @@ Useful links
|
|||||||
|
|
||||||
* How to install: https://docs.openstack.org/rally/latest/install_and_upgrade/install.html
|
* How to install: https://docs.openstack.org/rally/latest/install_and_upgrade/install.html
|
||||||
|
|
||||||
* How to set Rally up and launch your first scenario: https://rally.readthedocs.io/en/latest/tutorial/step_1_setting_up_env_and_running_benchmark_from_samples.html
|
* How to set Rally up and launch your first scenario: https://rally.readthedocs.io/en/latest/tutorial/step_1_setting_up_env_and_running_benchmark_from_samples.html
|
||||||
|
|
||||||
* More about Rally: https://rally.readthedocs.org/en/latest/
|
* More about Rally: https://docs.openstack.org/rally/latest/
|
||||||
|
|
||||||
* Rally release notes: https://rally.readthedocs.org/en/latest/release_notes.html
|
* Rally project info and release notes: https://docs.openstack.org/rally/latest/project_info/index.html
|
||||||
|
|
||||||
* How to add rally-gates: https://rally.readthedocs.org/en/latest/gates.html
|
* How to add rally-gates: https://docs.openstack.org/rally/latest/quick_start/gates.html#gate-jobs
|
||||||
|
|
||||||
* About plugins: https://rally.readthedocs.org/en/latest/plugins.html
|
* About plugins: https://docs.openstack.org/rally/latest/plugins/index.html
|
||||||
|
|
||||||
* Plugin samples: https://github.com/openstack/rally/tree/master/samples/plugins
|
* Plugin samples: https://github.com/openstack/rally/tree/master/samples/
|
||||||
|
|||||||
6
releasenotes/notes/cdm-scoping-8d9c307bad46bfa1.yaml
Normal file
6
releasenotes/notes/cdm-scoping-8d9c307bad46bfa1.yaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Each CDM collector can have its own CDM scoper now. This changed Scope
|
||||||
|
JSON schema definition for the audit template POST data. Please see audit
|
||||||
|
template create help message in python-watcherclient.
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
features:
|
features:
|
||||||
- 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 performance of a high priority VM by over utilizing
|
||||||
Last Level Cache.
|
Last Level Cache.
|
||||||
|
|||||||
@@ -57,14 +57,11 @@ master_doc = 'index'
|
|||||||
project = u'watcher'
|
project = u'watcher'
|
||||||
copyright = u'2016, Watcher developers'
|
copyright = u'2016, Watcher developers'
|
||||||
|
|
||||||
# The version info for the project you're documenting, acts as replacement for
|
# Release notes are version independent
|
||||||
# |version| and |release|, also used in various other places throughout the
|
|
||||||
# built documents.
|
|
||||||
#
|
|
||||||
# The short X.Y version.
|
# The short X.Y version.
|
||||||
version = watcher_version.version_info.release_string()
|
version = ''
|
||||||
# The full version, including alpha/beta/rc tags.
|
# The full version, including alpha/beta/rc tags.
|
||||||
release = watcher_version.version_string
|
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.
|
||||||
|
|||||||
207
releasenotes/source/locale/en_GB/LC_MESSAGES/releasenotes.po
Normal file
207
releasenotes/source/locale/en_GB/LC_MESSAGES/releasenotes.po
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
# Andi Chandler <andi@gowling.com>, 2016. #zanata
|
||||||
|
# Andi Chandler <andi@gowling.com>, 2017. #zanata
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: watcher 1.4.1.dev113\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2017-10-23 04:03+0000\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"PO-Revision-Date: 2017-10-21 06:22+0000\n"
|
||||||
|
"Last-Translator: Andi Chandler <andi@gowling.com>\n"
|
||||||
|
"Language-Team: English (United Kingdom)\n"
|
||||||
|
"Language: en-GB\n"
|
||||||
|
"X-Generator: Zanata 3.9.6\n"
|
||||||
|
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
|
||||||
|
|
||||||
|
msgid "0.29.0"
|
||||||
|
msgstr "0.29.0"
|
||||||
|
|
||||||
|
msgid "0.33.0"
|
||||||
|
msgstr "0.33.0"
|
||||||
|
|
||||||
|
msgid "0.34.0"
|
||||||
|
msgstr "0.34.0"
|
||||||
|
|
||||||
|
msgid "1.0.0"
|
||||||
|
msgstr "1.0.0"
|
||||||
|
|
||||||
|
msgid "1.1.0"
|
||||||
|
msgstr "1.1.0"
|
||||||
|
|
||||||
|
msgid "1.3.0"
|
||||||
|
msgstr "1.3.0"
|
||||||
|
|
||||||
|
msgid "1.4.0"
|
||||||
|
msgstr "1.4.0"
|
||||||
|
|
||||||
|
msgid "1.4.1"
|
||||||
|
msgstr "1.4.1"
|
||||||
|
|
||||||
|
msgid "Add a service supervisor to watch Watcher deamons."
|
||||||
|
msgstr "Add a service supervisor to watch Watcher daemons."
|
||||||
|
|
||||||
|
msgid "Add action for compute node power on/off"
|
||||||
|
msgstr "Add action for compute node power on/off"
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Add description property for dynamic action. Admin can see detail "
|
||||||
|
"information of any specify action."
|
||||||
|
msgstr ""
|
||||||
|
"Add description property for dynamic action. Admin can see detail "
|
||||||
|
"information of any specify action."
|
||||||
|
|
||||||
|
msgid "Add notifications related to Action object."
|
||||||
|
msgstr "Add notifications related to Action object."
|
||||||
|
|
||||||
|
msgid "Add notifications related to Action plan object."
|
||||||
|
msgstr "Add notifications related to Action plan object."
|
||||||
|
|
||||||
|
msgid "Add notifications related to Audit object."
|
||||||
|
msgstr "Add notifications related to Audit object."
|
||||||
|
|
||||||
|
msgid "Add notifications related to Service object."
|
||||||
|
msgstr "Add notifications related to Service object."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Add superseded state for an action plan if the cluster data model has "
|
||||||
|
"changed after it has been created."
|
||||||
|
msgstr ""
|
||||||
|
"Add superseded state for an action plan if the cluster data model has "
|
||||||
|
"changed after it has been created."
|
||||||
|
|
||||||
|
msgid "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 ""
|
||||||
|
"Added a generic scoring engine module, which will standarize 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 standardise 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 ""
|
||||||
|
"Added a new strategy based on the airflow of servers. This strategy makes "
|
||||||
|
"decisions to migrate VMs to make the airflow uniform."
|
||||||
|
msgstr ""
|
||||||
|
"Added a new strategy based on the airflow of servers. This strategy makes "
|
||||||
|
"decisions to migrate VMs to make the airflow uniform."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Added a standard way to both declare and fetch configuration options so that "
|
||||||
|
"whenever the administrator generates the Watcher configuration sample file, "
|
||||||
|
"it contains the configuration options of the plugins that are currently "
|
||||||
|
"available."
|
||||||
|
msgstr ""
|
||||||
|
"Added a standard way to both declare and fetch configuration options so that "
|
||||||
|
"whenever the administrator generates the Watcher configuration sample file, "
|
||||||
|
"it contains the configuration options of the plugins that are currently "
|
||||||
|
"available."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Added a strategy based on the VM workloads of hypervisors. This strategy "
|
||||||
|
"makes decisions to migrate workloads to make the total VM workloads of each "
|
||||||
|
"hypervisor balanced, when the total VM workloads of hypervisor reaches "
|
||||||
|
"threshold."
|
||||||
|
msgstr ""
|
||||||
|
"Added a strategy based on the VM workloads of hypervisors. This strategy "
|
||||||
|
"makes decisions to migrate workloads to make the total VM workloads of each "
|
||||||
|
"hypervisor balanced, when the total VM workloads of hypervisor reaches "
|
||||||
|
"threshold."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Added a strategy that monitors if there is a higher load on some hosts "
|
||||||
|
"compared to other hosts in the cluster and re-balances the work across hosts "
|
||||||
|
"to minimize the standard deviation of the loads in the cluster."
|
||||||
|
msgstr ""
|
||||||
|
"Added a strategy that monitors if there is a higher load on some hosts "
|
||||||
|
"compared to other hosts in the cluster and re-balances the work across hosts "
|
||||||
|
"to minimise the standard deviation of the loads in the cluster."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Added a way to add a new action without having to amend the source code of "
|
||||||
|
"the default planner."
|
||||||
|
msgstr ""
|
||||||
|
"Added a way to add a new action without having to amend the source code of "
|
||||||
|
"the default planner."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Added a way to compare the efficacy of different strategies for a give "
|
||||||
|
"optimization goal."
|
||||||
|
msgstr ""
|
||||||
|
"Added a way to compare the efficacy of different strategies for a give "
|
||||||
|
"optimisation goal."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Added a way to create periodic audit to be able to optimize continuously the "
|
||||||
|
"cloud infrastructure."
|
||||||
|
msgstr ""
|
||||||
|
"Added a way to create periodic audit to be able to continuously optimise the "
|
||||||
|
"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 ""
|
||||||
|
"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."
|
||||||
|
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 ""
|
||||||
|
"Added an in-memory cache of the cluster model built up and kept fresh via "
|
||||||
|
"notifications from services of interest in addition to periodic syncing "
|
||||||
|
"logic."
|
||||||
|
msgstr ""
|
||||||
|
"Added an in-memory cache of the cluster model built up and kept fresh via "
|
||||||
|
"notifications from services of interest in addition to periodic syncing "
|
||||||
|
"logic."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Added binding between apscheduler job and Watcher decision engine service. "
|
||||||
|
"It will allow to provide HA support in the future."
|
||||||
|
msgstr ""
|
||||||
|
"Added binding between apscheduler job and Watcher decision engine service. "
|
||||||
|
"It will allow to provide HA support in the future."
|
||||||
|
|
||||||
|
msgid "Added cinder cluster data model"
|
||||||
|
msgstr "Added cinder cluster data model"
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Added gnocchi support as data source for metrics. Administrator can change "
|
||||||
|
"data source for each strategy using config file."
|
||||||
|
msgstr ""
|
||||||
|
"Added Gnocchi support as data source for metrics. Administrator can change "
|
||||||
|
"data source for each strategy using config file."
|
||||||
|
|
||||||
|
msgid "Added policies to handle user rights to access Watcher API."
|
||||||
|
msgstr "Added policies to handle user rights to access Watcher API."
|
||||||
|
|
||||||
|
#, fuzzy
|
||||||
|
msgid "Contents:"
|
||||||
|
msgstr "Contents:"
|
||||||
|
|
||||||
|
#, fuzzy
|
||||||
|
msgid "Current Series Release Notes"
|
||||||
|
msgstr "Current Series Release Notes"
|
||||||
@@ -4,16 +4,16 @@
|
|||||||
|
|
||||||
apscheduler>=3.0.5 # MIT License
|
apscheduler>=3.0.5 # MIT License
|
||||||
enum34>=1.0.4;python_version=='2.7' or python_version=='2.6' or python_version=='3.3' # BSD
|
enum34>=1.0.4;python_version=='2.7' or python_version=='2.6' or python_version=='3.3' # BSD
|
||||||
jsonpatch>=1.16 # BSD
|
jsonpatch!=1.20,>=1.16 # BSD
|
||||||
keystoneauth1>=3.2.0 # Apache-2.0
|
keystoneauth1>=3.3.0 # Apache-2.0
|
||||||
jsonschema<3.0.0,>=2.6.0 # MIT
|
jsonschema<3.0.0,>=2.6.0 # MIT
|
||||||
keystonemiddleware>=4.17.0 # Apache-2.0
|
keystonemiddleware>=4.17.0 # Apache-2.0
|
||||||
lxml!=3.7.0,>=3.4.1 # BSD
|
lxml!=3.7.0,>=3.4.1 # BSD
|
||||||
croniter>=0.3.4 # MIT License
|
croniter>=0.3.4 # MIT License
|
||||||
oslo.concurrency>=3.20.0 # Apache-2.0
|
oslo.concurrency>=3.20.0 # Apache-2.0
|
||||||
oslo.cache>=1.26.0 # Apache-2.0
|
oslo.cache>=1.26.0 # Apache-2.0
|
||||||
oslo.config>=4.6.0 # Apache-2.0
|
oslo.config>=5.1.0 # Apache-2.0
|
||||||
oslo.context!=2.19.1,>=2.14.0 # Apache-2.0
|
oslo.context>=2.19.2 # Apache-2.0
|
||||||
oslo.db>=4.27.0 # Apache-2.0
|
oslo.db>=4.27.0 # Apache-2.0
|
||||||
oslo.i18n>=3.15.3 # Apache-2.0
|
oslo.i18n>=3.15.3 # Apache-2.0
|
||||||
oslo.log>=3.30.0 # Apache-2.0
|
oslo.log>=3.30.0 # Apache-2.0
|
||||||
@@ -22,7 +22,7 @@ oslo.policy>=1.23.0 # Apache-2.0
|
|||||||
oslo.reports>=1.18.0 # Apache-2.0
|
oslo.reports>=1.18.0 # Apache-2.0
|
||||||
oslo.serialization!=2.19.1,>=2.18.0 # Apache-2.0
|
oslo.serialization!=2.19.1,>=2.18.0 # Apache-2.0
|
||||||
oslo.service>=1.24.0 # Apache-2.0
|
oslo.service>=1.24.0 # Apache-2.0
|
||||||
oslo.utils>=3.28.0 # Apache-2.0
|
oslo.utils>=3.31.0 # Apache-2.0
|
||||||
oslo.versionedobjects>=1.28.0 # Apache-2.0
|
oslo.versionedobjects>=1.28.0 # Apache-2.0
|
||||||
PasteDeploy>=1.5.0 # MIT
|
PasteDeploy>=1.5.0 # MIT
|
||||||
pbr!=2.1.0,>=2.0.0 # Apache-2.0
|
pbr!=2.1.0,>=2.0.0 # Apache-2.0
|
||||||
@@ -39,7 +39,7 @@ python-neutronclient>=6.3.0 # Apache-2.0
|
|||||||
python-novaclient>=9.1.0 # Apache-2.0
|
python-novaclient>=9.1.0 # Apache-2.0
|
||||||
python-openstackclient>=3.12.0 # Apache-2.0
|
python-openstackclient>=3.12.0 # Apache-2.0
|
||||||
python-ironicclient>=1.14.0 # Apache-2.0
|
python-ironicclient>=1.14.0 # Apache-2.0
|
||||||
six>=1.9.0 # MIT
|
six>=1.10.0 # MIT
|
||||||
SQLAlchemy!=1.1.5,!=1.1.6,!=1.1.7,!=1.1.8,>=1.0.10 # MIT
|
SQLAlchemy!=1.1.5,!=1.1.6,!=1.1.7,!=1.1.8,>=1.0.10 # MIT
|
||||||
stevedore>=1.20.0 # Apache-2.0
|
stevedore>=1.20.0 # Apache-2.0
|
||||||
taskflow>=2.7.0 # Apache-2.0
|
taskflow>=2.7.0 # Apache-2.0
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ oslotest>=1.10.0 # Apache-2.0
|
|||||||
os-testr>=1.0.0 # Apache-2.0
|
os-testr>=1.0.0 # Apache-2.0
|
||||||
testrepository>=0.0.18 # Apache-2.0/BSD
|
testrepository>=0.0.18 # Apache-2.0/BSD
|
||||||
testscenarios>=0.4 # Apache-2.0/BSD
|
testscenarios>=0.4 # Apache-2.0/BSD
|
||||||
testtools>=1.4.0 # MIT
|
testtools>=2.2.0 # MIT
|
||||||
|
|
||||||
# Doc requirements
|
# Doc requirements
|
||||||
openstackdocstheme>=1.17.0 # Apache-2.0
|
openstackdocstheme>=1.17.0 # Apache-2.0
|
||||||
|
|||||||
3
tox.ini
3
tox.ini
@@ -14,7 +14,7 @@ deps = -r{toxinidir}/test-requirements.txt
|
|||||||
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
|
||||||
ostestr --concurrency=6 {posargs}
|
stestr run {posargs}
|
||||||
passenv = http_proxy HTTP_PROXY https_proxy HTTPS_PROXY no_proxy NO_PROXY
|
passenv = http_proxy HTTP_PROXY https_proxy HTTPS_PROXY no_proxy NO_PROXY
|
||||||
|
|
||||||
[testenv:pep8]
|
[testenv:pep8]
|
||||||
@@ -47,6 +47,7 @@ commands =
|
|||||||
oslo-config-generator --config-file etc/watcher/oslo-config-generator/watcher.conf
|
oslo-config-generator --config-file etc/watcher/oslo-config-generator/watcher.conf
|
||||||
|
|
||||||
[flake8]
|
[flake8]
|
||||||
|
filename = *.py,app.wsgi
|
||||||
show-source=True
|
show-source=True
|
||||||
ignore= H105,E123,E226,N320,H202
|
ignore= H105,E123,E226,N320,H202
|
||||||
builtins= _
|
builtins= _
|
||||||
|
|||||||
@@ -37,4 +37,3 @@ LOG.debug("Configuration:")
|
|||||||
CONF.log_opt_values(LOG, log.DEBUG)
|
CONF.log_opt_values(LOG, log.DEBUG)
|
||||||
|
|
||||||
application = app.VersionSelectorApplication()
|
application = app.VersionSelectorApplication()
|
||||||
|
|
||||||
|
|||||||
@@ -52,6 +52,8 @@ from watcher import objects
|
|||||||
|
|
||||||
class AuditPostType(wtypes.Base):
|
class AuditPostType(wtypes.Base):
|
||||||
|
|
||||||
|
name = wtypes.wsattr(wtypes.text, mandatory=False)
|
||||||
|
|
||||||
audit_template_uuid = wtypes.wsattr(types.uuid, mandatory=False)
|
audit_template_uuid = wtypes.wsattr(types.uuid, mandatory=False)
|
||||||
|
|
||||||
goal = wtypes.wsattr(wtypes.text, mandatory=False)
|
goal = wtypes.wsattr(wtypes.text, mandatory=False)
|
||||||
@@ -111,7 +113,25 @@ class AuditPostType(wtypes.Base):
|
|||||||
setattr(self, k, at_attr)
|
setattr(self, k, at_attr)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# Note: If audit name was not provided, used a default name
|
||||||
|
if not self.name:
|
||||||
|
if self.strategy:
|
||||||
|
strategy = objects.Strategy.get(context, self.strategy)
|
||||||
|
self.name = "%s-%s" % (strategy.name,
|
||||||
|
datetime.datetime.utcnow().isoformat())
|
||||||
|
elif self.audit_template_uuid:
|
||||||
|
audit_template = objects.AuditTemplate.get(
|
||||||
|
context, self.audit_template_uuid)
|
||||||
|
self.name = "%s-%s" % (audit_template.name,
|
||||||
|
datetime.datetime.utcnow().isoformat())
|
||||||
|
else:
|
||||||
|
goal = objects.Goal.get(context, self.goal)
|
||||||
|
self.name = "%s-%s" % (goal.name,
|
||||||
|
datetime.datetime.utcnow().isoformat())
|
||||||
|
|
||||||
return Audit(
|
return Audit(
|
||||||
|
name=self.name,
|
||||||
audit_type=self.audit_type,
|
audit_type=self.audit_type,
|
||||||
parameters=self.parameters,
|
parameters=self.parameters,
|
||||||
goal_id=self.goal,
|
goal_id=self.goal,
|
||||||
@@ -233,6 +253,9 @@ class Audit(base.APIBase):
|
|||||||
uuid = types.uuid
|
uuid = types.uuid
|
||||||
"""Unique UUID for this audit"""
|
"""Unique UUID for this audit"""
|
||||||
|
|
||||||
|
name = wtypes.text
|
||||||
|
"""Name of this audit"""
|
||||||
|
|
||||||
audit_type = wtypes.text
|
audit_type = wtypes.text
|
||||||
"""Type of this audit"""
|
"""Type of this audit"""
|
||||||
|
|
||||||
@@ -301,7 +324,7 @@ class Audit(base.APIBase):
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def _convert_with_links(audit, url, expand=True):
|
def _convert_with_links(audit, url, expand=True):
|
||||||
if not expand:
|
if not expand:
|
||||||
audit.unset_fields_except(['uuid', 'audit_type', 'state',
|
audit.unset_fields_except(['uuid', 'name', 'audit_type', 'state',
|
||||||
'goal_uuid', 'interval', 'scope',
|
'goal_uuid', 'interval', 'scope',
|
||||||
'strategy_uuid', 'goal_name',
|
'strategy_uuid', 'goal_name',
|
||||||
'strategy_name', 'auto_trigger',
|
'strategy_name', 'auto_trigger',
|
||||||
@@ -324,6 +347,7 @@ class Audit(base.APIBase):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def sample(cls, expand=True):
|
def sample(cls, expand=True):
|
||||||
sample = cls(uuid='27e3153e-d5bf-4b7e-b517-fb518e17f34c',
|
sample = cls(uuid='27e3153e-d5bf-4b7e-b517-fb518e17f34c',
|
||||||
|
name='My Audit',
|
||||||
audit_type='ONESHOT',
|
audit_type='ONESHOT',
|
||||||
state='PENDING',
|
state='PENDING',
|
||||||
created_at=datetime.datetime.utcnow(),
|
created_at=datetime.datetime.utcnow(),
|
||||||
@@ -483,17 +507,17 @@ class AuditsController(rest.RestController):
|
|||||||
resource_url,
|
resource_url,
|
||||||
goal=goal)
|
goal=goal)
|
||||||
|
|
||||||
@wsme_pecan.wsexpose(Audit, types.uuid)
|
@wsme_pecan.wsexpose(Audit, wtypes.text)
|
||||||
def get_one(self, audit_uuid):
|
def get_one(self, audit):
|
||||||
"""Retrieve information about the given audit.
|
"""Retrieve information about the given audit.
|
||||||
|
|
||||||
:param audit_uuid: UUID of a audit.
|
:param audit_uuid: UUID or name of an audit.
|
||||||
"""
|
"""
|
||||||
if self.from_audits:
|
if self.from_audits:
|
||||||
raise exception.OperationNotPermitted
|
raise exception.OperationNotPermitted
|
||||||
|
|
||||||
context = pecan.request.context
|
context = pecan.request.context
|
||||||
rpc_audit = api_utils.get_resource('Audit', audit_uuid)
|
rpc_audit = api_utils.get_resource('Audit', audit)
|
||||||
policy.enforce(context, 'audit:get', rpc_audit, action='audit:get')
|
policy.enforce(context, 'audit:get', rpc_audit, action='audit:get')
|
||||||
|
|
||||||
return Audit.convert_with_links(rpc_audit)
|
return Audit.convert_with_links(rpc_audit)
|
||||||
@@ -551,11 +575,11 @@ class AuditsController(rest.RestController):
|
|||||||
return Audit.convert_with_links(new_audit)
|
return Audit.convert_with_links(new_audit)
|
||||||
|
|
||||||
@wsme.validate(types.uuid, [AuditPatchType])
|
@wsme.validate(types.uuid, [AuditPatchType])
|
||||||
@wsme_pecan.wsexpose(Audit, types.uuid, body=[AuditPatchType])
|
@wsme_pecan.wsexpose(Audit, wtypes.text, body=[AuditPatchType])
|
||||||
def patch(self, audit_uuid, patch):
|
def patch(self, audit, patch):
|
||||||
"""Update an existing audit.
|
"""Update an existing audit.
|
||||||
|
|
||||||
:param audit_uuid: UUID of a audit.
|
:param auditd: UUID or name of a audit.
|
||||||
:param patch: a json PATCH document to apply to this audit.
|
:param patch: a json PATCH document to apply to this audit.
|
||||||
"""
|
"""
|
||||||
if self.from_audits:
|
if self.from_audits:
|
||||||
@@ -563,7 +587,7 @@ class AuditsController(rest.RestController):
|
|||||||
|
|
||||||
context = pecan.request.context
|
context = pecan.request.context
|
||||||
audit_to_update = api_utils.get_resource(
|
audit_to_update = api_utils.get_resource(
|
||||||
'Audit', audit_uuid, eager=True)
|
'Audit', audit, eager=True)
|
||||||
policy.enforce(context, 'audit:update', audit_to_update,
|
policy.enforce(context, 'audit:update', audit_to_update,
|
||||||
action='audit:update')
|
action='audit:update')
|
||||||
|
|
||||||
@@ -600,15 +624,15 @@ 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, types.uuid, status_code=204)
|
@wsme_pecan.wsexpose(None, wtypes.text, status_code=204)
|
||||||
def delete(self, audit_uuid):
|
def delete(self, audit):
|
||||||
"""Delete a audit.
|
"""Delete an audit.
|
||||||
|
|
||||||
:param audit_uuid: UUID of a audit.
|
:param audit: UUID or name of an audit.
|
||||||
"""
|
"""
|
||||||
context = pecan.request.context
|
context = pecan.request.context
|
||||||
audit_to_delete = api_utils.get_resource(
|
audit_to_delete = api_utils.get_resource(
|
||||||
'Audit', audit_uuid, eager=True)
|
'Audit', audit, eager=True)
|
||||||
policy.enforce(context, 'audit:update', audit_to_delete,
|
policy.enforce(context, 'audit:update', audit_to_delete,
|
||||||
action='audit:update')
|
action='audit:update')
|
||||||
|
|
||||||
|
|||||||
@@ -51,6 +51,8 @@ import wsme
|
|||||||
from wsme import types as wtypes
|
from wsme import types as wtypes
|
||||||
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
|
||||||
@@ -61,9 +63,11 @@ from watcher.common import context as context_utils
|
|||||||
from watcher.common import exception
|
from watcher.common import exception
|
||||||
from watcher.common import policy
|
from watcher.common import policy
|
||||||
from watcher.common import utils as common_utils
|
from watcher.common import utils as common_utils
|
||||||
from watcher.decision_engine.scope import default
|
from watcher.decision_engine.loading import default as default_loading
|
||||||
from watcher import objects
|
from watcher import objects
|
||||||
|
|
||||||
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class AuditTemplatePostType(wtypes.Base):
|
class AuditTemplatePostType(wtypes.Base):
|
||||||
_ctx = context_utils.make_context()
|
_ctx = context_utils.make_context()
|
||||||
@@ -94,6 +98,27 @@ class AuditTemplatePostType(wtypes.Base):
|
|||||||
scope=self.scope,
|
scope=self.scope,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _build_schema():
|
||||||
|
SCHEMA = {
|
||||||
|
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": AuditTemplatePostType._get_schemas(),
|
||||||
|
"additionalProperties": False
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SCHEMA
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _get_schemas():
|
||||||
|
collectors = default_loading.ClusterDataModelCollectorLoader(
|
||||||
|
).list_available()
|
||||||
|
schemas = {k: c.SCHEMA for k, c
|
||||||
|
in collectors.items() if hasattr(c, "SCHEMA")}
|
||||||
|
return schemas
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def validate(audit_template):
|
def validate(audit_template):
|
||||||
available_goals = objects.Goal.list(AuditTemplatePostType._ctx)
|
available_goals = objects.Goal.list(AuditTemplatePostType._ctx)
|
||||||
@@ -106,23 +131,25 @@ class AuditTemplatePostType(wtypes.Base):
|
|||||||
else:
|
else:
|
||||||
raise exception.InvalidGoal(goal=audit_template.goal)
|
raise exception.InvalidGoal(goal=audit_template.goal)
|
||||||
|
|
||||||
common_utils.Draft4Validator(
|
if audit_template.scope:
|
||||||
default.DefaultScope.DEFAULT_SCHEMA).validate(audit_template.scope)
|
common_utils.Draft4Validator(
|
||||||
|
AuditTemplatePostType._build_schema()
|
||||||
|
).validate(audit_template.scope)
|
||||||
|
|
||||||
include_host_aggregates = False
|
include_host_aggregates = False
|
||||||
exclude_host_aggregates = False
|
exclude_host_aggregates = False
|
||||||
for rule in audit_template.scope:
|
for rule in audit_template.scope[0]['compute']:
|
||||||
if 'host_aggregates' in rule:
|
if 'host_aggregates' in rule:
|
||||||
include_host_aggregates = True
|
include_host_aggregates = True
|
||||||
elif 'exclude' in rule:
|
elif 'exclude' in rule:
|
||||||
for resource in rule['exclude']:
|
for resource in rule['exclude']:
|
||||||
if 'host_aggregates' in resource:
|
if 'host_aggregates' in resource:
|
||||||
exclude_host_aggregates = True
|
exclude_host_aggregates = True
|
||||||
if include_host_aggregates and exclude_host_aggregates:
|
if include_host_aggregates and exclude_host_aggregates:
|
||||||
raise exception.Invalid(
|
raise exception.Invalid(
|
||||||
message=_(
|
message=_(
|
||||||
"host_aggregates can't be "
|
"host_aggregates can't be "
|
||||||
"included and excluded together"))
|
"included and excluded together"))
|
||||||
|
|
||||||
if audit_template.strategy:
|
if audit_template.strategy:
|
||||||
available_strategies = objects.Strategy.list(
|
available_strategies = objects.Strategy.list(
|
||||||
|
|||||||
@@ -36,15 +36,20 @@ class ChangeNovaServiceState(base.BaseAction):
|
|||||||
schema = Schema({
|
schema = Schema({
|
||||||
'resource_id': str,
|
'resource_id': str,
|
||||||
'state': str,
|
'state': str,
|
||||||
|
'disabled_reason': str,
|
||||||
})
|
})
|
||||||
|
|
||||||
The `resource_id` references a nova-compute service name (list of available
|
The `resource_id` references a nova-compute service name (list of available
|
||||||
nova-compute services is returned by this command: ``nova service-list
|
nova-compute services is returned by this command: ``nova service-list
|
||||||
--binary nova-compute``).
|
--binary nova-compute``).
|
||||||
The `state` value should either be `ONLINE` or `OFFLINE`.
|
The `state` value should either be `ONLINE` or `OFFLINE`.
|
||||||
|
The `disabled_reason` references the reason why Watcher disables this
|
||||||
|
nova-compute service. The value should be with `watcher_` prefix, such as
|
||||||
|
`watcher_disabled`, `watcher_maintaining`.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
STATE = 'state'
|
STATE = 'state'
|
||||||
|
REASON = 'disabled_reason'
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def schema(self):
|
def schema(self):
|
||||||
@@ -61,6 +66,10 @@ class ChangeNovaServiceState(base.BaseAction):
|
|||||||
element.ServiceState.OFFLINE.value,
|
element.ServiceState.OFFLINE.value,
|
||||||
element.ServiceState.ENABLED.value,
|
element.ServiceState.ENABLED.value,
|
||||||
element.ServiceState.DISABLED.value]
|
element.ServiceState.DISABLED.value]
|
||||||
|
},
|
||||||
|
'disabled_reason': {
|
||||||
|
'type': 'string',
|
||||||
|
"minlength": 1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'required': ['resource_id', 'state'],
|
'required': ['resource_id', 'state'],
|
||||||
@@ -75,6 +84,10 @@ class ChangeNovaServiceState(base.BaseAction):
|
|||||||
def state(self):
|
def state(self):
|
||||||
return self.input_parameters.get(self.STATE)
|
return self.input_parameters.get(self.STATE)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def reason(self):
|
||||||
|
return self.input_parameters.get(self.REASON)
|
||||||
|
|
||||||
def execute(self):
|
def execute(self):
|
||||||
target_state = None
|
target_state = None
|
||||||
if self.state == element.ServiceState.DISABLED.value:
|
if self.state == element.ServiceState.DISABLED.value:
|
||||||
@@ -100,7 +113,7 @@ class ChangeNovaServiceState(base.BaseAction):
|
|||||||
if state is True:
|
if state is True:
|
||||||
return nova.enable_service_nova_compute(self.host)
|
return nova.enable_service_nova_compute(self.host)
|
||||||
else:
|
else:
|
||||||
return nova.disable_service_nova_compute(self.host)
|
return nova.disable_service_nova_compute(self.host, self.reason)
|
||||||
|
|
||||||
def pre_condition(self):
|
def pre_condition(self):
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -112,18 +112,9 @@ class Migrate(base.BaseAction):
|
|||||||
result = nova.live_migrate_instance(instance_id=self.instance_uuid,
|
result = nova.live_migrate_instance(instance_id=self.instance_uuid,
|
||||||
dest_hostname=destination)
|
dest_hostname=destination)
|
||||||
except nova_helper.nvexceptions.ClientException as e:
|
except nova_helper.nvexceptions.ClientException as e:
|
||||||
if e.code == 400:
|
LOG.debug("Nova client exception occurred while live "
|
||||||
LOG.debug("Live migration of instance %s failed. "
|
"migrating instance %s.Exception: %s" %
|
||||||
"Trying to live migrate using block migration."
|
(self.instance_uuid, e))
|
||||||
% self.instance_uuid)
|
|
||||||
result = nova.live_migrate_instance(
|
|
||||||
instance_id=self.instance_uuid,
|
|
||||||
dest_hostname=destination,
|
|
||||||
block_migration=True)
|
|
||||||
else:
|
|
||||||
LOG.debug("Nova client exception occurred while live "
|
|
||||||
"migrating instance %s.Exception: %s" %
|
|
||||||
(self.instance_uuid, e))
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
LOG.exception(e)
|
LOG.exception(e)
|
||||||
LOG.critical("Unexpected error occurred. Migration failed for "
|
LOG.critical("Unexpected error occurred. Migration failed for "
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ class VolumeMigrate(base.BaseAction):
|
|||||||
'migration_type': str, # choices -> "swap", "cold"
|
'migration_type': str, # choices -> "swap", "cold"
|
||||||
'destination_node': str,
|
'destination_node': str,
|
||||||
'destination_type': str,
|
'destination_type': str,
|
||||||
)}
|
})
|
||||||
|
|
||||||
The `resource_id` is the UUID of cinder volume to migrate.
|
The `resource_id` is the UUID of cinder volume to migrate.
|
||||||
The `destination_node` is the destination block storage pool name.
|
The `destination_node` is the destination block storage pool name.
|
||||||
|
|||||||
@@ -20,13 +20,13 @@
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log as logging
|
from oslo_log import log
|
||||||
|
|
||||||
from watcher.api import scheduling
|
from watcher.api import scheduling
|
||||||
from watcher.common import service
|
from watcher.common import service
|
||||||
from watcher import conf
|
from watcher import conf
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
CONF = conf.CONF
|
CONF = conf.CONF
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -20,14 +20,14 @@
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from oslo_log import log as logging
|
from oslo_log import log
|
||||||
|
|
||||||
from watcher.applier import manager
|
from watcher.applier import manager
|
||||||
from watcher.applier import sync
|
from watcher.applier import sync
|
||||||
from watcher.common import service as watcher_service
|
from watcher.common import service as watcher_service
|
||||||
from watcher import conf
|
from watcher import conf
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
CONF = conf.CONF
|
CONF = conf.CONF
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from oslo_log import log as logging
|
from oslo_log import log
|
||||||
|
|
||||||
from watcher.common import service as watcher_service
|
from watcher.common import service as watcher_service
|
||||||
from watcher import conf
|
from watcher import conf
|
||||||
@@ -29,7 +29,7 @@ from watcher.decision_engine import manager
|
|||||||
from watcher.decision_engine import scheduling
|
from watcher.decision_engine import scheduling
|
||||||
from watcher.decision_engine import sync
|
from watcher.decision_engine import sync
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
CONF = conf.CONF
|
CONF = conf.CONF
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -20,13 +20,13 @@
|
|||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from oslo_log import log as logging
|
from oslo_log import log
|
||||||
|
|
||||||
from watcher.common import service as service
|
from watcher.common import service as service
|
||||||
from watcher import conf
|
from watcher import conf
|
||||||
from watcher.decision_engine import sync
|
from watcher.decision_engine import sync
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
CONF = conf.CONF
|
CONF = conf.CONF
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -165,7 +165,8 @@ class CinderHelper(object):
|
|||||||
|
|
||||||
def check_migrated(self, volume, retry_interval=10):
|
def check_migrated(self, volume, retry_interval=10):
|
||||||
volume = self.get_volume(volume)
|
volume = self.get_volume(volume)
|
||||||
while getattr(volume, 'migration_status') == 'migrating':
|
final_status = ('success', 'error')
|
||||||
|
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 {0}'.format(volume))
|
LOG.debug('Waiting the migration of {0}'.format(volume))
|
||||||
time.sleep(retry_interval)
|
time.sleep(retry_interval)
|
||||||
|
|||||||
@@ -11,11 +11,11 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from oslo_context import context
|
from oslo_context import context
|
||||||
from oslo_log import log as logging
|
from oslo_log import log
|
||||||
from oslo_utils import timeutils
|
from oslo_utils import timeutils
|
||||||
import six
|
import six
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class RequestContext(context.RequestContext):
|
class RequestContext(context.RequestContext):
|
||||||
|
|||||||
@@ -26,14 +26,14 @@ import functools
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
from keystoneclient import exceptions as keystone_exceptions
|
from keystoneclient import exceptions as keystone_exceptions
|
||||||
from oslo_log import log as logging
|
from oslo_log import log
|
||||||
import six
|
import six
|
||||||
|
|
||||||
from watcher._i18n import _
|
from watcher._i18n import _
|
||||||
|
|
||||||
from watcher import conf
|
from watcher import conf
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
CONF = conf.CONF
|
CONF = conf.CONF
|
||||||
|
|
||||||
@@ -249,7 +249,7 @@ class AuditNotFound(ResourceNotFound):
|
|||||||
|
|
||||||
|
|
||||||
class AuditAlreadyExists(Conflict):
|
class AuditAlreadyExists(Conflict):
|
||||||
msg_fmt = _("An audit with UUID %(uuid)s already exists")
|
msg_fmt = _("An audit with UUID or name %(audit)s already exists")
|
||||||
|
|
||||||
|
|
||||||
class AuditIntervalNotSpecified(Invalid):
|
class AuditIntervalNotSpecified(Invalid):
|
||||||
|
|||||||
@@ -200,11 +200,7 @@ class NovaHelper(object):
|
|||||||
new_image_name = getattr(image, "name")
|
new_image_name = getattr(image, "name")
|
||||||
|
|
||||||
instance_name = getattr(instance, "name")
|
instance_name = getattr(instance, "name")
|
||||||
flavordict = getattr(instance, "flavor")
|
flavor_name = instance.flavor.get('original_name')
|
||||||
# a_dict = dict([flavorstr.strip('{}').split(":"),])
|
|
||||||
flavor_id = flavordict["id"]
|
|
||||||
flavor = self.nova.flavors.get(flavor_id)
|
|
||||||
flavor_name = getattr(flavor, "name")
|
|
||||||
keypair_name = getattr(instance, "key_name")
|
keypair_name = getattr(instance, "key_name")
|
||||||
|
|
||||||
addresses = getattr(instance, "addresses")
|
addresses = getattr(instance, "addresses")
|
||||||
@@ -422,8 +418,7 @@ class NovaHelper(object):
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def live_migrate_instance(self, instance_id, dest_hostname,
|
def live_migrate_instance(self, instance_id, dest_hostname, retry=120):
|
||||||
block_migration=False, retry=120):
|
|
||||||
"""This method does a live migration of a given instance
|
"""This method does a live migration of a given instance
|
||||||
|
|
||||||
This method uses the Nova built-in live_migrate()
|
This method uses the Nova built-in live_migrate()
|
||||||
@@ -436,7 +431,6 @@ class NovaHelper(object):
|
|||||||
:param dest_hostname: the name of the destination compute node, if
|
:param dest_hostname: the name of the destination compute node, if
|
||||||
destination_node is None, nova scheduler choose
|
destination_node is None, nova scheduler choose
|
||||||
the destination host
|
the destination host
|
||||||
:param block_migration: No shared storage is required.
|
|
||||||
"""
|
"""
|
||||||
LOG.debug("Trying to live migrate instance %s " % (instance_id))
|
LOG.debug("Trying to live migrate instance %s " % (instance_id))
|
||||||
|
|
||||||
@@ -450,8 +444,9 @@ class NovaHelper(object):
|
|||||||
LOG.debug(
|
LOG.debug(
|
||||||
"Instance %s found on host '%s'." % (instance_id, host_name))
|
"Instance %s found on host '%s'." % (instance_id, host_name))
|
||||||
|
|
||||||
instance.live_migrate(host=dest_hostname,
|
# From nova api version 2.25(Mitaka release), the default value of
|
||||||
block_migration=block_migration)
|
# block_migration is None which is mapped to 'auto'.
|
||||||
|
instance.live_migrate(host=dest_hostname)
|
||||||
|
|
||||||
instance = self.nova.servers.get(instance_id)
|
instance = self.nova.servers.get(instance_id)
|
||||||
|
|
||||||
@@ -479,6 +474,9 @@ class NovaHelper(object):
|
|||||||
'OS-EXT-SRV-ATTR:host') != dest_hostname \
|
'OS-EXT-SRV-ATTR:host') != dest_hostname \
|
||||||
and retry:
|
and retry:
|
||||||
instance = self.nova.servers.get(instance.id)
|
instance = self.nova.servers.get(instance.id)
|
||||||
|
if not getattr(instance, 'OS-EXT-STS:task_state'):
|
||||||
|
LOG.debug("Instance task state: %s is null" % instance_id)
|
||||||
|
break
|
||||||
LOG.debug(
|
LOG.debug(
|
||||||
'Waiting the migration of {0} to {1}'.format(
|
'Waiting the migration of {0} to {1}'.format(
|
||||||
instance,
|
instance,
|
||||||
@@ -543,9 +541,10 @@ class NovaHelper(object):
|
|||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def disable_service_nova_compute(self, hostname):
|
def disable_service_nova_compute(self, hostname, reason=None):
|
||||||
if self.nova.services.disable(host=hostname,
|
if self.nova.services.disable_log_reason(host=hostname,
|
||||||
binary='nova-compute'). \
|
binary='nova-compute',
|
||||||
|
reason=reason). \
|
||||||
status == 'disabled':
|
status == 'disabled':
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
@@ -768,10 +767,9 @@ class NovaHelper(object):
|
|||||||
|
|
||||||
# Make sure all security groups exist
|
# Make sure all security groups exist
|
||||||
for sec_group_name in sec_group_list:
|
for sec_group_name in sec_group_list:
|
||||||
try:
|
group_id = self.get_security_group_id_from_name(sec_group_name)
|
||||||
self.nova.security_groups.find(name=sec_group_name)
|
|
||||||
|
|
||||||
except nvexceptions.NotFound:
|
if not group_id:
|
||||||
LOG.debug("Security group '%s' not found " % sec_group_name)
|
LOG.debug("Security group '%s' not found " % sec_group_name)
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -818,6 +816,14 @@ class NovaHelper(object):
|
|||||||
|
|
||||||
return instance
|
return instance
|
||||||
|
|
||||||
|
def get_security_group_id_from_name(self, group_name="default"):
|
||||||
|
"""This method returns the security group of the provided group name"""
|
||||||
|
security_groups = self.neutron.list_security_groups(name=group_name)
|
||||||
|
|
||||||
|
security_group_id = security_groups['security_groups'][0]['id']
|
||||||
|
|
||||||
|
return security_group_id
|
||||||
|
|
||||||
def get_network_id_from_name(self, net_name="private"):
|
def get_network_id_from_name(self, net_name="private"):
|
||||||
"""This method returns the unique id of the provided network name"""
|
"""This method returns the unique id of the provided network name"""
|
||||||
networks = self.neutron.list_networks(name=net_name)
|
networks = self.neutron.list_networks(name=net_name)
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import string
|
|||||||
from croniter import croniter
|
from croniter import croniter
|
||||||
|
|
||||||
from jsonschema import validators
|
from jsonschema import validators
|
||||||
from oslo_log import log as logging
|
from oslo_log import log
|
||||||
from oslo_utils import strutils
|
from oslo_utils import strutils
|
||||||
from oslo_utils import uuidutils
|
from oslo_utils import uuidutils
|
||||||
import six
|
import six
|
||||||
@@ -35,7 +35,7 @@ from watcher import conf
|
|||||||
|
|
||||||
CONF = conf.CONF
|
CONF = conf.CONF
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class Struct(dict):
|
class Struct(dict):
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ _DEFAULT_SQL_CONNECTION = 'sqlite:///{0}'.format(
|
|||||||
paths.state_path_def('watcher.sqlite'))
|
paths.state_path_def('watcher.sqlite'))
|
||||||
|
|
||||||
database = cfg.OptGroup(name='database',
|
database = cfg.OptGroup(name='database',
|
||||||
title='Configuration Options for database')
|
title='Configuration Options for database')
|
||||||
|
|
||||||
SQL_OPTS = [
|
SQL_OPTS = [
|
||||||
cfg.StrOpt('mysql_engine',
|
cfg.StrOpt('mysql_engine',
|
||||||
|
|||||||
@@ -401,6 +401,16 @@ class BaseConnection(object):
|
|||||||
:raises: :py:class:`~.AuditNotFound`
|
:raises: :py:class:`~.AuditNotFound`
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
def get_audit_by_name(self, context, audit_name, eager=False):
|
||||||
|
"""Return an audit.
|
||||||
|
|
||||||
|
:param context: The security context
|
||||||
|
:param audit_name: The name of an audit.
|
||||||
|
:param eager: If True, also loads One-to-X data (Default: False)
|
||||||
|
:returns: An audit.
|
||||||
|
:raises: :py:class:`~.AuditNotFound`
|
||||||
|
"""
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def destroy_audit(self, audit_id):
|
def destroy_audit(self, audit_id):
|
||||||
"""Destroy an audit and all associated action plans.
|
"""Destroy an audit and all associated action plans.
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
"""add name for audit
|
||||||
|
|
||||||
|
Revision ID: 3cfc94cecf4e
|
||||||
|
Revises: d098df6021e2
|
||||||
|
Create Date: 2017-07-19 15:44:57.661099
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '3cfc94cecf4e'
|
||||||
|
down_revision = 'd09a5945e4a0'
|
||||||
|
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
op.add_column('audits', sa.Column('name', sa.String(length=63), nullable=True))
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
op.drop_column('audits', 'name')
|
||||||
@@ -659,6 +659,14 @@ class Connection(api.BaseConnection):
|
|||||||
if not values.get('uuid'):
|
if not values.get('uuid'):
|
||||||
values['uuid'] = utils.generate_uuid()
|
values['uuid'] = utils.generate_uuid()
|
||||||
|
|
||||||
|
query = model_query(models.Audit)
|
||||||
|
query = query.filter_by(name=values.get('name'),
|
||||||
|
deleted_at=None)
|
||||||
|
|
||||||
|
if len(query.all()) > 0:
|
||||||
|
raise exception.AuditAlreadyExists(
|
||||||
|
audit=values['name'])
|
||||||
|
|
||||||
if values.get('state') is None:
|
if values.get('state') is None:
|
||||||
values['state'] = objects.audit.State.PENDING
|
values['state'] = objects.audit.State.PENDING
|
||||||
|
|
||||||
@@ -668,7 +676,7 @@ class Connection(api.BaseConnection):
|
|||||||
try:
|
try:
|
||||||
audit = self._create(models.Audit, values)
|
audit = self._create(models.Audit, values)
|
||||||
except db_exc.DBDuplicateEntry:
|
except db_exc.DBDuplicateEntry:
|
||||||
raise exception.AuditAlreadyExists(uuid=values['uuid'])
|
raise exception.AuditAlreadyExists(audit=values['uuid'])
|
||||||
return audit
|
return audit
|
||||||
|
|
||||||
def _get_audit(self, context, fieldname, value, eager):
|
def _get_audit(self, context, fieldname, value, eager):
|
||||||
@@ -686,6 +694,10 @@ class Connection(api.BaseConnection):
|
|||||||
return self._get_audit(
|
return self._get_audit(
|
||||||
context, fieldname="uuid", value=audit_uuid, eager=eager)
|
context, fieldname="uuid", value=audit_uuid, eager=eager)
|
||||||
|
|
||||||
|
def get_audit_by_name(self, context, audit_name, eager=False):
|
||||||
|
return self._get_audit(
|
||||||
|
context, fieldname="name", value=audit_name, eager=eager)
|
||||||
|
|
||||||
def destroy_audit(self, audit_id):
|
def destroy_audit(self, audit_id):
|
||||||
def is_audit_referenced(session, audit_id):
|
def is_audit_referenced(session, audit_id):
|
||||||
"""Checks whether the audit is referenced by action_plan(s)."""
|
"""Checks whether the audit is referenced by action_plan(s)."""
|
||||||
|
|||||||
@@ -166,10 +166,12 @@ class Audit(Base):
|
|||||||
__tablename__ = 'audits'
|
__tablename__ = 'audits'
|
||||||
__table_args__ = (
|
__table_args__ = (
|
||||||
UniqueConstraint('uuid', name='uniq_audits0uuid'),
|
UniqueConstraint('uuid', name='uniq_audits0uuid'),
|
||||||
|
UniqueConstraint('name', 'deleted', name='uniq_audits0name'),
|
||||||
table_args()
|
table_args()
|
||||||
)
|
)
|
||||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||||
uuid = Column(String(36))
|
uuid = Column(String(36))
|
||||||
|
name = Column(String(63), nullable=True)
|
||||||
audit_type = Column(String(20))
|
audit_type = Column(String(20))
|
||||||
state = Column(String(20), nullable=True)
|
state = Column(String(20), nullable=True)
|
||||||
parameters = Column(JSONEncodedDict, nullable=True)
|
parameters = Column(JSONEncodedDict, nullable=True)
|
||||||
@@ -197,7 +199,7 @@ class ActionPlan(Base):
|
|||||||
audit_id = Column(Integer, ForeignKey('audits.id'), nullable=False)
|
audit_id = Column(Integer, ForeignKey('audits.id'), nullable=False)
|
||||||
strategy_id = Column(Integer, ForeignKey('strategies.id'), nullable=False)
|
strategy_id = Column(Integer, ForeignKey('strategies.id'), nullable=False)
|
||||||
state = Column(String(20), nullable=True)
|
state = Column(String(20), nullable=True)
|
||||||
global_efficacy = Column(JSONEncodedDict, nullable=True)
|
global_efficacy = Column(JSONEncodedList, nullable=True)
|
||||||
|
|
||||||
audit = orm.relationship(Audit, foreign_keys=audit_id, lazy=None)
|
audit = orm.relationship(Audit, foreign_keys=audit_id, lazy=None)
|
||||||
strategy = orm.relationship(Strategy, foreign_keys=strategy_id, lazy=None)
|
strategy = orm.relationship(Strategy, foreign_keys=strategy_id, lazy=None)
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ class ContinuousAuditHandler(base.AuditHandler):
|
|||||||
[job for job in self.scheduler.get_jobs()
|
[job for job in self.scheduler.get_jobs()
|
||||||
if job.name == 'execute_audit' and
|
if job.name == 'execute_audit' and
|
||||||
job.args[0].uuid == audit.uuid][0].remove()
|
job.args[0].uuid == audit.uuid][0].remove()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@@ -131,6 +131,9 @@ class ContinuousAuditHandler(base.AuditHandler):
|
|||||||
scheduler_job_args = [
|
scheduler_job_args = [
|
||||||
job.args for job in self.scheduler.get_jobs()
|
job.args for job in self.scheduler.get_jobs()
|
||||||
if job.name == 'execute_audit']
|
if job.name == 'execute_audit']
|
||||||
|
for args in scheduler_job_args:
|
||||||
|
if self._is_audit_inactive(args[0]):
|
||||||
|
scheduler_job_args.remove(args)
|
||||||
for audit in audits:
|
for audit in audits:
|
||||||
# if audit is not presented in scheduled audits yet.
|
# if audit is not presented in scheduled audits yet.
|
||||||
if audit.uuid not in [arg[0].uuid for arg in scheduler_job_args]:
|
if audit.uuid not in [arg[0].uuid for arg in scheduler_job_args]:
|
||||||
|
|||||||
@@ -57,7 +57,8 @@ class EfficacySpecification(object):
|
|||||||
efficacy indicators related to this spec
|
efficacy indicators related to this spec
|
||||||
:type indicators_map: :py:class:`~.IndicatorsMap` instance
|
:type indicators_map: :py:class:`~.IndicatorsMap` instance
|
||||||
:raises: NotImplementedError
|
:raises: NotImplementedError
|
||||||
:returns: :py:class:`~.Indicator` instance
|
:returns: :py:class:`~.Indicator` instance list, each instance specify
|
||||||
|
global efficacy for different openstack resource.
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
|||||||
@@ -40,14 +40,16 @@ class ServerConsolidation(base.EfficacySpecification):
|
|||||||
|
|
||||||
def get_global_efficacy_indicator(self, indicators_map=None):
|
def get_global_efficacy_indicator(self, indicators_map=None):
|
||||||
value = 0
|
value = 0
|
||||||
|
global_efficacy = []
|
||||||
if indicators_map and indicators_map.compute_nodes_count > 0:
|
if indicators_map and indicators_map.compute_nodes_count > 0:
|
||||||
value = (float(indicators_map.released_compute_nodes_count) /
|
value = (float(indicators_map.released_compute_nodes_count) /
|
||||||
float(indicators_map.compute_nodes_count)) * 100
|
float(indicators_map.compute_nodes_count)) * 100
|
||||||
|
global_efficacy.append(efficacy.Indicator(
|
||||||
return efficacy.Indicator(
|
|
||||||
name="released_nodes_ratio",
|
name="released_nodes_ratio",
|
||||||
description=_("Ratio of released compute nodes divided by the "
|
description=_("Ratio of released compute nodes divided by the "
|
||||||
"total number of enabled compute nodes."),
|
"total number of enabled compute nodes."),
|
||||||
unit='%',
|
unit='%',
|
||||||
value=value,
|
value=value,
|
||||||
)
|
))
|
||||||
|
|
||||||
|
return global_efficacy
|
||||||
|
|||||||
@@ -172,7 +172,7 @@ class NoisyNeighborOptimization(base.Goal):
|
|||||||
"""NoisyNeighborOptimization
|
"""NoisyNeighborOptimization
|
||||||
|
|
||||||
This goal is used to identify and migrate a Noisy Neighbor -
|
This goal is used to identify and migrate a Noisy Neighbor -
|
||||||
a low priority VM that negatively affects peformance of a high priority VM
|
a low priority VM that negatively affects performance of a high priority VM
|
||||||
in terms of IPC by over utilizing Last Level Cache.
|
in terms of IPC by over utilizing Last Level Cache.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|||||||
@@ -128,6 +128,7 @@ class BaseClusterDataModelCollector(loadable.LoadableSingleton):
|
|||||||
self.osc = osc if osc else clients.OpenStackClients()
|
self.osc = osc if osc else clients.OpenStackClients()
|
||||||
self._cluster_data_model = None
|
self._cluster_data_model = None
|
||||||
self.lock = threading.RLock()
|
self.lock = threading.RLock()
|
||||||
|
self._audit_scope_handler = None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def cluster_data_model(self):
|
def cluster_data_model(self):
|
||||||
@@ -156,6 +157,11 @@ class BaseClusterDataModelCollector(loadable.LoadableSingleton):
|
|||||||
def set_cluster_data_model_as_stale(self):
|
def set_cluster_data_model_as_stale(self):
|
||||||
self.cluster_data_model = self.STALE_MODEL
|
self.cluster_data_model = self.STALE_MODEL
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def get_audit_scope_handler(self, audit_scope):
|
||||||
|
"""Get audit scope handler"""
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def execute(self):
|
def execute(self):
|
||||||
"""Build a cluster data model"""
|
"""Build a cluster data model"""
|
||||||
|
|||||||
@@ -54,6 +54,9 @@ class CinderClusterDataModelCollector(base.BaseClusterDataModelCollector):
|
|||||||
cinder.VolumeResizeEnd(self)
|
cinder.VolumeResizeEnd(self)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
def get_audit_scope_handler(self, audit_scope):
|
||||||
|
return None
|
||||||
|
|
||||||
def execute(self):
|
def execute(self):
|
||||||
"""Build the storage cluster data model"""
|
"""Build the storage cluster data model"""
|
||||||
LOG.debug("Building latest Cinder cluster data model")
|
LOG.debug("Building latest Cinder cluster data model")
|
||||||
|
|||||||
@@ -60,4 +60,5 @@ class CollectorManager(object):
|
|||||||
:returns: cluster data model collector plugin
|
:returns: cluster data model collector plugin
|
||||||
:rtype: :py:class:`~.BaseClusterDataModelCollector`
|
:rtype: :py:class:`~.BaseClusterDataModelCollector`
|
||||||
"""
|
"""
|
||||||
return self.collector_loader.load(name, osc=osc)
|
return self.collector_loader.load(
|
||||||
|
name, osc=osc)
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ from watcher.decision_engine.model.collector import base
|
|||||||
from watcher.decision_engine.model import element
|
from watcher.decision_engine.model import element
|
||||||
from watcher.decision_engine.model import model_root
|
from watcher.decision_engine.model import model_root
|
||||||
from watcher.decision_engine.model.notification import nova
|
from watcher.decision_engine.model.notification import nova
|
||||||
|
from watcher.decision_engine.scope import compute as compute_scope
|
||||||
|
|
||||||
LOG = log.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
@@ -32,6 +33,109 @@ class NovaClusterDataModelCollector(base.BaseClusterDataModelCollector):
|
|||||||
representation of the resources exposed by the compute service.
|
representation of the resources exposed by the compute service.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
HOST_AGGREGATES = "#/items/properties/compute/host_aggregates/"
|
||||||
|
SCHEMA = {
|
||||||
|
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"host_aggregates": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"anyOf": [
|
||||||
|
{"$ref": HOST_AGGREGATES + "id"},
|
||||||
|
{"$ref": HOST_AGGREGATES + "name"},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"availability_zones": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": False
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"exclude": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"instances": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"uuid": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": False
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compute_nodes": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": False
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"host_aggregates": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"anyOf": [
|
||||||
|
{"$ref": HOST_AGGREGATES + "id"},
|
||||||
|
{"$ref": HOST_AGGREGATES + "name"},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"instance_metadata": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": False
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": False
|
||||||
|
},
|
||||||
|
"host_aggregates": {
|
||||||
|
"id": {
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"oneOf": [
|
||||||
|
{"type": "integer"},
|
||||||
|
{"enum": ["*"]}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": False
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": False
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": False
|
||||||
|
}
|
||||||
|
|
||||||
def __init__(self, config, osc=None):
|
def __init__(self, config, osc=None):
|
||||||
super(NovaClusterDataModelCollector, self).__init__(config, osc)
|
super(NovaClusterDataModelCollector, self).__init__(config, osc)
|
||||||
|
|
||||||
@@ -53,8 +157,14 @@ class NovaClusterDataModelCollector(base.BaseClusterDataModelCollector):
|
|||||||
nova.LegacyInstanceUpdated(self),
|
nova.LegacyInstanceUpdated(self),
|
||||||
nova.LegacyInstanceDeletedEnd(self),
|
nova.LegacyInstanceDeletedEnd(self),
|
||||||
nova.LegacyLiveMigratedEnd(self),
|
nova.LegacyLiveMigratedEnd(self),
|
||||||
|
nova.LegacyInstanceResizeConfirmEnd(self),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
def get_audit_scope_handler(self, audit_scope):
|
||||||
|
self._audit_scope_handler = compute_scope.ComputeScope(
|
||||||
|
audit_scope, self.config)
|
||||||
|
return self._audit_scope_handler
|
||||||
|
|
||||||
def execute(self):
|
def execute(self):
|
||||||
"""Build the compute cluster data model"""
|
"""Build the compute cluster data model"""
|
||||||
LOG.debug("Building latest Nova cluster data model")
|
LOG.debug("Building latest Nova cluster data model")
|
||||||
@@ -139,7 +249,8 @@ class ModelBuilder(object):
|
|||||||
"disk_capacity": node.local_gb,
|
"disk_capacity": node.local_gb,
|
||||||
"vcpus": node.vcpus,
|
"vcpus": node.vcpus,
|
||||||
"state": node.state,
|
"state": node.state,
|
||||||
"status": node.status}
|
"status": node.status,
|
||||||
|
"disabled_reason": compute_service.disabled_reason}
|
||||||
|
|
||||||
compute_node = element.ComputeNode(**node_attributes)
|
compute_node = element.ComputeNode(**node_attributes)
|
||||||
# compute_node = self._build_node("physical", "compute", "hypervisor",
|
# compute_node = self._build_node("physical", "compute", "hypervisor",
|
||||||
|
|||||||
@@ -36,8 +36,8 @@ class ComputeNode(compute_resource.ComputeResource):
|
|||||||
"id": wfields.StringField(),
|
"id": wfields.StringField(),
|
||||||
"hostname": wfields.StringField(),
|
"hostname": wfields.StringField(),
|
||||||
"status": wfields.StringField(default=ServiceState.ENABLED.value),
|
"status": wfields.StringField(default=ServiceState.ENABLED.value),
|
||||||
|
"disabled_reason": wfields.StringField(nullable=True),
|
||||||
"state": wfields.StringField(default=ServiceState.ONLINE.value),
|
"state": wfields.StringField(default=ServiceState.ONLINE.value),
|
||||||
|
|
||||||
"memory": wfields.NonNegativeIntegerField(),
|
"memory": wfields.NonNegativeIntegerField(),
|
||||||
"disk": wfields.IntegerField(),
|
"disk": wfields.IntegerField(),
|
||||||
"disk_capacity": wfields.NonNegativeIntegerField(),
|
"disk_capacity": wfields.NonNegativeIntegerField(),
|
||||||
|
|||||||
@@ -122,11 +122,15 @@ class NovaNotification(base.NotificationEndpoint):
|
|||||||
node_status = (
|
node_status = (
|
||||||
element.ServiceState.DISABLED.value
|
element.ServiceState.DISABLED.value
|
||||||
if node_data['disabled'] else element.ServiceState.ENABLED.value)
|
if node_data['disabled'] else element.ServiceState.ENABLED.value)
|
||||||
|
disabled_reason = (
|
||||||
|
node_data['disabled_reason']
|
||||||
|
if node_data['disabled'] else None)
|
||||||
|
|
||||||
node.update({
|
node.update({
|
||||||
'hostname': node_data['host'],
|
'hostname': node_data['host'],
|
||||||
'state': node_state,
|
'state': node_state,
|
||||||
'status': node_status,
|
'status': node_status,
|
||||||
|
'disabled_reason': disabled_reason,
|
||||||
})
|
})
|
||||||
|
|
||||||
def create_compute_node(self, node_hostname):
|
def create_compute_node(self, node_hostname):
|
||||||
@@ -466,3 +470,30 @@ class LegacyLiveMigratedEnd(UnversionedNotificationEndpoint):
|
|||||||
instance = self.get_or_create_instance(instance_uuid, node_uuid)
|
instance = self.get_or_create_instance(instance_uuid, node_uuid)
|
||||||
|
|
||||||
self.legacy_update_instance(instance, payload)
|
self.legacy_update_instance(instance, payload)
|
||||||
|
|
||||||
|
|
||||||
|
class LegacyInstanceResizeConfirmEnd(UnversionedNotificationEndpoint):
|
||||||
|
|
||||||
|
@property
|
||||||
|
def filter_rule(self):
|
||||||
|
"""Nova compute.instance.resize.confirm.end filter"""
|
||||||
|
return filtering.NotificationFilter(
|
||||||
|
publisher_id=self.publisher_id_regex,
|
||||||
|
event_type='compute.instance.resize.confirm.end',
|
||||||
|
)
|
||||||
|
|
||||||
|
def info(self, ctxt, publisher_id, event_type, payload, metadata):
|
||||||
|
ctxt.request_id = metadata['message_id']
|
||||||
|
ctxt.project_domain = event_type
|
||||||
|
LOG.info("Event '%(event)s' received from %(publisher)s "
|
||||||
|
"with metadata %(metadata)s" %
|
||||||
|
dict(event=event_type,
|
||||||
|
publisher=publisher_id,
|
||||||
|
metadata=metadata))
|
||||||
|
LOG.debug(payload)
|
||||||
|
|
||||||
|
instance_uuid = payload['instance_id']
|
||||||
|
node_uuid = payload.get('node')
|
||||||
|
instance = self.get_or_create_instance(instance_uuid, node_uuid)
|
||||||
|
|
||||||
|
self.legacy_update_instance(instance, payload)
|
||||||
|
|||||||
@@ -24,113 +24,11 @@ from watcher.decision_engine.scope import base
|
|||||||
LOG = log.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class DefaultScope(base.BaseScope):
|
class ComputeScope(base.BaseScope):
|
||||||
"""Default Audit Scope Handler"""
|
"""Compute Audit Scope Handler"""
|
||||||
|
|
||||||
DEFAULT_SCHEMA = {
|
|
||||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"host_aggregates": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"anyOf": [
|
|
||||||
{"$ref": "#/host_aggregates/id"},
|
|
||||||
{"$ref": "#/host_aggregates/name"},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"availability_zones": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"name": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"additionalProperties": False
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"exclude": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"instances": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"uuid": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"additionalProperties": False
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"compute_nodes": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"name": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"additionalProperties": False
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"host_aggregates": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"anyOf": [
|
|
||||||
{"$ref": "#/host_aggregates/id"},
|
|
||||||
{"$ref": "#/host_aggregates/name"},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"instance_metadata": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "object"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"additionalProperties": False
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"additionalProperties": False
|
|
||||||
},
|
|
||||||
"host_aggregates": {
|
|
||||||
"id": {
|
|
||||||
"properties": {
|
|
||||||
"id": {
|
|
||||||
"oneOf": [
|
|
||||||
{"type": "integer"},
|
|
||||||
{"enum": ["*"]}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"additionalProperties": False
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"properties": {
|
|
||||||
"name": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"additionalProperties": False
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"additionalProperties": False
|
|
||||||
}
|
|
||||||
|
|
||||||
def __init__(self, scope, config, osc=None):
|
def __init__(self, scope, config, osc=None):
|
||||||
super(DefaultScope, self).__init__(scope, config)
|
super(ComputeScope, self).__init__(scope, config)
|
||||||
self._osc = osc
|
self._osc = osc
|
||||||
self.wrapper = nova_helper.NovaHelper(osc=self._osc)
|
self.wrapper = nova_helper.NovaHelper(osc=self._osc)
|
||||||
|
|
||||||
@@ -16,13 +16,13 @@
|
|||||||
|
|
||||||
import numbers
|
import numbers
|
||||||
|
|
||||||
from oslo_log import log as logging
|
from oslo_log import log
|
||||||
|
|
||||||
from watcher._i18n import _
|
from watcher._i18n import _
|
||||||
from watcher.common import exception
|
from watcher.common import exception
|
||||||
from watcher.common import utils
|
from watcher.common import utils
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class IndicatorsMap(utils.Struct):
|
class IndicatorsMap(utils.Struct):
|
||||||
@@ -62,7 +62,7 @@ class Efficacy(object):
|
|||||||
self.indicators = []
|
self.indicators = []
|
||||||
# Used to compute the global efficacy
|
# Used to compute the global efficacy
|
||||||
self._indicators_mapping = IndicatorsMap()
|
self._indicators_mapping = IndicatorsMap()
|
||||||
self.global_efficacy = None
|
self.global_efficacy = []
|
||||||
|
|
||||||
def set_efficacy_indicators(self, **indicators_map):
|
def set_efficacy_indicators(self, **indicators_map):
|
||||||
"""Set the efficacy indicators
|
"""Set the efficacy indicators
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ from watcher.common.loader import loadable
|
|||||||
from watcher.common import utils
|
from watcher.common import utils
|
||||||
from watcher.decision_engine.loading import default as loading
|
from watcher.decision_engine.loading import default as loading
|
||||||
from watcher.decision_engine.model.collector import manager
|
from watcher.decision_engine.model.collector import manager
|
||||||
from watcher.decision_engine.scope import default as default_scope
|
|
||||||
from watcher.decision_engine.solution import default
|
from watcher.decision_engine.solution import default
|
||||||
from watcher.decision_engine.strategy.common import level
|
from watcher.decision_engine.strategy.common import level
|
||||||
|
|
||||||
@@ -85,7 +84,6 @@ class BaseStrategy(loadable.Loadable):
|
|||||||
self._storage_model = None
|
self._storage_model = None
|
||||||
self._input_parameters = utils.Struct()
|
self._input_parameters = utils.Struct()
|
||||||
self._audit_scope = None
|
self._audit_scope = None
|
||||||
self._audit_scope_handler = None
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
@@ -182,7 +180,9 @@ class BaseStrategy(loadable.Loadable):
|
|||||||
if self._compute_model is None:
|
if self._compute_model is None:
|
||||||
collector = self.collector_manager.get_cluster_model_collector(
|
collector = self.collector_manager.get_cluster_model_collector(
|
||||||
'compute', osc=self.osc)
|
'compute', osc=self.osc)
|
||||||
self._compute_model = self.audit_scope_handler.get_scoped_model(
|
audit_scope_handler = collector.get_audit_scope_handler(
|
||||||
|
audit_scope=self.audit_scope)
|
||||||
|
self._compute_model = audit_scope_handler.get_scoped_model(
|
||||||
collector.get_latest_cluster_data_model())
|
collector.get_latest_cluster_data_model())
|
||||||
|
|
||||||
if not self._compute_model:
|
if not self._compute_model:
|
||||||
@@ -253,13 +253,6 @@ class BaseStrategy(loadable.Loadable):
|
|||||||
def audit_scope(self, s):
|
def audit_scope(self, s):
|
||||||
self._audit_scope = s
|
self._audit_scope = s
|
||||||
|
|
||||||
@property
|
|
||||||
def audit_scope_handler(self):
|
|
||||||
if not self._audit_scope_handler:
|
|
||||||
self._audit_scope_handler = default_scope.DefaultScope(
|
|
||||||
self.audit_scope, self.config)
|
|
||||||
return self._audit_scope_handler
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
return self._name
|
return self._name
|
||||||
@@ -331,6 +324,8 @@ class UnclassifiedStrategy(BaseStrategy):
|
|||||||
@six.add_metaclass(abc.ABCMeta)
|
@six.add_metaclass(abc.ABCMeta)
|
||||||
class ServerConsolidationBaseStrategy(BaseStrategy):
|
class ServerConsolidationBaseStrategy(BaseStrategy):
|
||||||
|
|
||||||
|
REASON_FOR_DISABLE = 'watcher_disabled'
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_goal_name(cls):
|
def get_goal_name(cls):
|
||||||
return "server_consolidation"
|
return "server_consolidation"
|
||||||
|
|||||||
@@ -158,7 +158,7 @@ class BasicConsolidation(base.ServerConsolidationBaseStrategy):
|
|||||||
cfg.StrOpt(
|
cfg.StrOpt(
|
||||||
"datasource",
|
"datasource",
|
||||||
help="Data source to use in order to query the needed metrics",
|
help="Data source to use in order to query the needed metrics",
|
||||||
default="ceilometer",
|
default="gnocchi",
|
||||||
choices=["ceilometer", "monasca", "gnocchi"]),
|
choices=["ceilometer", "monasca", "gnocchi"]),
|
||||||
cfg.BoolOpt(
|
cfg.BoolOpt(
|
||||||
"check_optimize_metadata",
|
"check_optimize_metadata",
|
||||||
@@ -415,8 +415,9 @@ class BasicConsolidation(base.ServerConsolidationBaseStrategy):
|
|||||||
|
|
||||||
return self.calculate_weight(instance, total_cores_used, 0, 0)
|
return self.calculate_weight(instance, total_cores_used, 0, 0)
|
||||||
|
|
||||||
def add_change_service_state(self, resource_id, state):
|
def add_action_disable_node(self, resource_id):
|
||||||
parameters = {'state': state}
|
parameters = {'state': element.ServiceState.DISABLED.value,
|
||||||
|
'disabled_reason': self.REASON_FOR_DISABLE}
|
||||||
self.solution.add_action(action_type=self.CHANGE_NOVA_SERVICE_STATE,
|
self.solution.add_action(action_type=self.CHANGE_NOVA_SERVICE_STATE,
|
||||||
resource_id=resource_id,
|
resource_id=resource_id,
|
||||||
input_parameters=parameters)
|
input_parameters=parameters)
|
||||||
@@ -472,9 +473,7 @@ class BasicConsolidation(base.ServerConsolidationBaseStrategy):
|
|||||||
mig_destination_node.uuid)
|
mig_destination_node.uuid)
|
||||||
|
|
||||||
if len(self.compute_model.get_node_instances(mig_source_node)) == 0:
|
if len(self.compute_model.get_node_instances(mig_source_node)) == 0:
|
||||||
self.add_change_service_state(mig_source_node.
|
self.add_action_disable_node(mig_source_node.uuid)
|
||||||
uuid,
|
|
||||||
element.ServiceState.DISABLED.value)
|
|
||||||
self.number_of_released_nodes += 1
|
self.number_of_released_nodes += 1
|
||||||
|
|
||||||
def calculate_num_migrations(self, sorted_instances, node_to_release,
|
def calculate_num_migrations(self, sorted_instances, node_to_release,
|
||||||
|
|||||||
@@ -71,8 +71,8 @@ class OutletTempControl(base.ThermalOptimizationBaseStrategy):
|
|||||||
|
|
||||||
*Spec URL*
|
*Spec URL*
|
||||||
|
|
||||||
https://github.com/openstack/watcher-specs/blob/master/specs/mitaka/approved/outlet-temperature-based-strategy.rst
|
https://github.com/openstack/watcher-specs/blob/master/specs/mitaka/implemented/outlet-temperature-based-strategy.rst
|
||||||
""" # noqa
|
"""
|
||||||
|
|
||||||
# The meter to report outlet temperature in ceilometer
|
# The meter to report outlet temperature in ceilometer
|
||||||
MIGRATION = "migrate"
|
MIGRATION = "migrate"
|
||||||
@@ -167,7 +167,7 @@ class OutletTempControl(base.ThermalOptimizationBaseStrategy):
|
|||||||
cfg.StrOpt(
|
cfg.StrOpt(
|
||||||
"datasource",
|
"datasource",
|
||||||
help="Data source to use in order to query the needed metrics",
|
help="Data source to use in order to query the needed metrics",
|
||||||
default="ceilometer",
|
default="gnocchi",
|
||||||
choices=["ceilometer", "gnocchi"])
|
choices=["ceilometer", "gnocchi"])
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -210,7 +210,7 @@ class UniformAirflow(base.BaseStrategy):
|
|||||||
cfg.StrOpt(
|
cfg.StrOpt(
|
||||||
"datasource",
|
"datasource",
|
||||||
help="Data source to use in order to query the needed metrics",
|
help="Data source to use in order to query the needed metrics",
|
||||||
default="ceilometer",
|
default="gnocchi",
|
||||||
choices=["ceilometer", "gnocchi"])
|
choices=["ceilometer", "gnocchi"])
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ class VMWorkloadConsolidation(base.ServerConsolidationBaseStrategy):
|
|||||||
cfg.StrOpt(
|
cfg.StrOpt(
|
||||||
"datasource",
|
"datasource",
|
||||||
help="Data source to use in order to query the needed metrics",
|
help="Data source to use in order to query the needed metrics",
|
||||||
default="ceilometer",
|
default="gnocchi",
|
||||||
choices=["ceilometer", "gnocchi"])
|
choices=["ceilometer", "gnocchi"])
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -228,7 +228,8 @@ class VMWorkloadConsolidation(base.ServerConsolidationBaseStrategy):
|
|||||||
:param node: node object
|
:param node: node object
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
params = {'state': element.ServiceState.DISABLED.value}
|
params = {'state': element.ServiceState.DISABLED.value,
|
||||||
|
'disabled_reason': self.REASON_FOR_DISABLE}
|
||||||
self.solution.add_action(
|
self.solution.add_action(
|
||||||
action_type=self.CHANGE_NOVA_SERVICE_STATE,
|
action_type=self.CHANGE_NOVA_SERVICE_STATE,
|
||||||
resource_id=node.uuid,
|
resource_id=node.uuid,
|
||||||
@@ -244,7 +245,8 @@ class VMWorkloadConsolidation(base.ServerConsolidationBaseStrategy):
|
|||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
instance_state_str = self.get_instance_state_str(instance)
|
instance_state_str = self.get_instance_state_str(instance)
|
||||||
if instance_state_str != element.InstanceState.ACTIVE.value:
|
if instance_state_str not in (element.InstanceState.ACTIVE.value,
|
||||||
|
element.InstanceState.PAUSED.value):
|
||||||
# Watcher currently only supports live VM migration and block live
|
# Watcher currently only supports live VM migration and block live
|
||||||
# VM migration which both requires migrated VM to be active.
|
# VM migration which both requires migrated VM to be active.
|
||||||
# When supported, the cold migration may be used as a fallback
|
# When supported, the cold migration may be used as a fallback
|
||||||
|
|||||||
@@ -187,7 +187,7 @@ class WorkloadBalance(base.WorkloadStabilizationBaseStrategy):
|
|||||||
cfg.StrOpt(
|
cfg.StrOpt(
|
||||||
"datasource",
|
"datasource",
|
||||||
help="Data source to use in order to query the needed metrics",
|
help="Data source to use in order to query the needed metrics",
|
||||||
default="ceilometer",
|
default="gnocchi",
|
||||||
choices=["ceilometer", "gnocchi"])
|
choices=["ceilometer", "gnocchi"])
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -172,7 +172,7 @@ class WorkloadStabilization(base.WorkloadStabilizationBaseStrategy):
|
|||||||
cfg.StrOpt(
|
cfg.StrOpt(
|
||||||
"datasource",
|
"datasource",
|
||||||
help="Data source to use in order to query the needed metrics",
|
help="Data source to use in order to query the needed metrics",
|
||||||
default="ceilometer",
|
default="gnocchi",
|
||||||
choices=["ceilometer", "gnocchi"])
|
choices=["ceilometer", "gnocchi"])
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -45,12 +45,13 @@ class TerseActionPlanPayload(notificationbase.NotificationPayloadBase):
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Version 1.0: Initial version
|
# Version 1.0: Initial version
|
||||||
VERSION = '1.0'
|
# Version 1.1: Changed 'global_efficacy' type Dictionary to List
|
||||||
|
VERSION = '1.1'
|
||||||
|
|
||||||
fields = {
|
fields = {
|
||||||
'uuid': wfields.UUIDField(),
|
'uuid': wfields.UUIDField(),
|
||||||
'state': wfields.StringField(),
|
'state': wfields.StringField(),
|
||||||
'global_efficacy': wfields.FlexibleDictField(nullable=True),
|
'global_efficacy': wfields.FlexibleListOfDictField(nullable=True),
|
||||||
'audit_uuid': wfields.UUIDField(),
|
'audit_uuid': wfields.UUIDField(),
|
||||||
'strategy_uuid': wfields.UUIDField(nullable=True),
|
'strategy_uuid': wfields.UUIDField(nullable=True),
|
||||||
|
|
||||||
@@ -80,7 +81,8 @@ class ActionPlanPayload(TerseActionPlanPayload):
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Version 1.0: Initial version
|
# Version 1.0: Initial version
|
||||||
VERSION = '1.0'
|
# Vesrsion 1.1: changed global_efficacy type
|
||||||
|
VERSION = '1.1'
|
||||||
|
|
||||||
fields = {
|
fields = {
|
||||||
'audit': wfields.ObjectField('TerseAuditPayload'),
|
'audit': wfields.ObjectField('TerseAuditPayload'),
|
||||||
@@ -112,7 +114,8 @@ class ActionPlanStateUpdatePayload(notificationbase.NotificationPayloadBase):
|
|||||||
@base.WatcherObjectRegistry.register_notification
|
@base.WatcherObjectRegistry.register_notification
|
||||||
class ActionPlanCreatePayload(ActionPlanPayload):
|
class ActionPlanCreatePayload(ActionPlanPayload):
|
||||||
# Version 1.0: Initial version
|
# Version 1.0: Initial version
|
||||||
VERSION = '1.0'
|
# Version 1.1: Changed global_efficacy_type
|
||||||
|
VERSION = '1.1'
|
||||||
fields = {}
|
fields = {}
|
||||||
|
|
||||||
def __init__(self, action_plan, audit, strategy):
|
def __init__(self, action_plan, audit, strategy):
|
||||||
@@ -125,7 +128,8 @@ class ActionPlanCreatePayload(ActionPlanPayload):
|
|||||||
@base.WatcherObjectRegistry.register_notification
|
@base.WatcherObjectRegistry.register_notification
|
||||||
class ActionPlanUpdatePayload(ActionPlanPayload):
|
class ActionPlanUpdatePayload(ActionPlanPayload):
|
||||||
# Version 1.0: Initial version
|
# Version 1.0: Initial version
|
||||||
VERSION = '1.0'
|
# Version 1.1: Changed global_efficacy_type
|
||||||
|
VERSION = '1.1'
|
||||||
fields = {
|
fields = {
|
||||||
'state_update': wfields.ObjectField('ActionPlanStateUpdatePayload'),
|
'state_update': wfields.ObjectField('ActionPlanStateUpdatePayload'),
|
||||||
}
|
}
|
||||||
@@ -141,7 +145,8 @@ class ActionPlanUpdatePayload(ActionPlanPayload):
|
|||||||
@base.WatcherObjectRegistry.register_notification
|
@base.WatcherObjectRegistry.register_notification
|
||||||
class ActionPlanActionPayload(ActionPlanPayload):
|
class ActionPlanActionPayload(ActionPlanPayload):
|
||||||
# Version 1.0: Initial version
|
# Version 1.0: Initial version
|
||||||
VERSION = '1.0'
|
# Version 1.1: Changed global_efficacy_type
|
||||||
|
VERSION = '1.1'
|
||||||
fields = {
|
fields = {
|
||||||
'fault': wfields.ObjectField('ExceptionPayload', nullable=True),
|
'fault': wfields.ObjectField('ExceptionPayload', nullable=True),
|
||||||
}
|
}
|
||||||
@@ -157,7 +162,8 @@ class ActionPlanActionPayload(ActionPlanPayload):
|
|||||||
@base.WatcherObjectRegistry.register_notification
|
@base.WatcherObjectRegistry.register_notification
|
||||||
class ActionPlanDeletePayload(ActionPlanPayload):
|
class ActionPlanDeletePayload(ActionPlanPayload):
|
||||||
# Version 1.0: Initial version
|
# Version 1.0: Initial version
|
||||||
VERSION = '1.0'
|
# Version 1.1: Changed global_efficacy_type
|
||||||
|
VERSION = '1.1'
|
||||||
fields = {}
|
fields = {}
|
||||||
|
|
||||||
def __init__(self, action_plan, audit, strategy):
|
def __init__(self, action_plan, audit, strategy):
|
||||||
@@ -170,7 +176,8 @@ class ActionPlanDeletePayload(ActionPlanPayload):
|
|||||||
@base.WatcherObjectRegistry.register_notification
|
@base.WatcherObjectRegistry.register_notification
|
||||||
class ActionPlanCancelPayload(ActionPlanPayload):
|
class ActionPlanCancelPayload(ActionPlanPayload):
|
||||||
# Version 1.0: Initial version
|
# Version 1.0: Initial version
|
||||||
VERSION = '1.0'
|
# Version 1.1: Changed global_efficacy_type
|
||||||
|
VERSION = '1.1'
|
||||||
fields = {
|
fields = {
|
||||||
'fault': wfields.ObjectField('ExceptionPayload', nullable=True),
|
'fault': wfields.ObjectField('ExceptionPayload', nullable=True),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ CONF = cfg.CONF
|
|||||||
class TerseAuditPayload(notificationbase.NotificationPayloadBase):
|
class TerseAuditPayload(notificationbase.NotificationPayloadBase):
|
||||||
SCHEMA = {
|
SCHEMA = {
|
||||||
'uuid': ('audit', 'uuid'),
|
'uuid': ('audit', 'uuid'),
|
||||||
|
'name': ('audit', 'name'),
|
||||||
'audit_type': ('audit', 'audit_type'),
|
'audit_type': ('audit', 'audit_type'),
|
||||||
'state': ('audit', 'state'),
|
'state': ('audit', 'state'),
|
||||||
'parameters': ('audit', 'parameters'),
|
'parameters': ('audit', 'parameters'),
|
||||||
@@ -51,10 +51,12 @@ class TerseAuditPayload(notificationbase.NotificationPayloadBase):
|
|||||||
# Version 1.1: Added 'auto_trigger' boolean field,
|
# Version 1.1: Added 'auto_trigger' boolean field,
|
||||||
# Added 'next_run_time' DateTime field,
|
# Added 'next_run_time' DateTime field,
|
||||||
# 'interval' type has been changed from Integer to String
|
# 'interval' type has been changed from Integer to String
|
||||||
VERSION = '1.1'
|
# Version 1.2: Added 'name' string field
|
||||||
|
VERSION = '1.2'
|
||||||
|
|
||||||
fields = {
|
fields = {
|
||||||
'uuid': wfields.UUIDField(),
|
'uuid': wfields.UUIDField(),
|
||||||
|
'name': wfields.StringField(),
|
||||||
'audit_type': wfields.StringField(),
|
'audit_type': wfields.StringField(),
|
||||||
'state': wfields.StringField(),
|
'state': wfields.StringField(),
|
||||||
'parameters': wfields.FlexibleDictField(nullable=True),
|
'parameters': wfields.FlexibleDictField(nullable=True),
|
||||||
@@ -80,7 +82,7 @@ class TerseAuditPayload(notificationbase.NotificationPayloadBase):
|
|||||||
class AuditPayload(TerseAuditPayload):
|
class AuditPayload(TerseAuditPayload):
|
||||||
SCHEMA = {
|
SCHEMA = {
|
||||||
'uuid': ('audit', 'uuid'),
|
'uuid': ('audit', 'uuid'),
|
||||||
|
'name': ('audit', 'name'),
|
||||||
'audit_type': ('audit', 'audit_type'),
|
'audit_type': ('audit', 'audit_type'),
|
||||||
'state': ('audit', 'state'),
|
'state': ('audit', 'state'),
|
||||||
'parameters': ('audit', 'parameters'),
|
'parameters': ('audit', 'parameters'),
|
||||||
@@ -97,7 +99,8 @@ class AuditPayload(TerseAuditPayload):
|
|||||||
# Version 1.0: Initial version
|
# Version 1.0: Initial version
|
||||||
# Version 1.1: Added 'auto_trigger' field,
|
# Version 1.1: Added 'auto_trigger' field,
|
||||||
# Added 'next_run_time' field
|
# Added 'next_run_time' field
|
||||||
VERSION = '1.1'
|
# Version 1.2: Added 'name' string field
|
||||||
|
VERSION = '1.2'
|
||||||
|
|
||||||
fields = {
|
fields = {
|
||||||
'goal': wfields.ObjectField('GoalPayload'),
|
'goal': wfields.ObjectField('GoalPayload'),
|
||||||
|
|||||||
@@ -105,7 +105,8 @@ class ActionPlan(base.WatcherPersistentObject, base.WatcherObject,
|
|||||||
# Version 1.1: Added 'audit' and 'strategy' object field
|
# Version 1.1: Added 'audit' and 'strategy' object field
|
||||||
# Version 1.2: audit_id is not nullable anymore
|
# Version 1.2: audit_id is not nullable anymore
|
||||||
# Version 2.0: Removed 'first_action_id' object field
|
# Version 2.0: Removed 'first_action_id' object field
|
||||||
VERSION = '2.0'
|
# Version 2.1: Changed global_efficacy type
|
||||||
|
VERSION = '2.1'
|
||||||
|
|
||||||
dbapi = db_api.get_instance()
|
dbapi = db_api.get_instance()
|
||||||
|
|
||||||
@@ -115,7 +116,7 @@ class ActionPlan(base.WatcherPersistentObject, base.WatcherObject,
|
|||||||
'audit_id': wfields.IntegerField(),
|
'audit_id': wfields.IntegerField(),
|
||||||
'strategy_id': wfields.IntegerField(),
|
'strategy_id': wfields.IntegerField(),
|
||||||
'state': wfields.StringField(nullable=True),
|
'state': wfields.StringField(nullable=True),
|
||||||
'global_efficacy': wfields.FlexibleDictField(nullable=True),
|
'global_efficacy': wfields.FlexibleListOfDictField(nullable=True),
|
||||||
|
|
||||||
'audit': wfields.ObjectField('Audit', nullable=True),
|
'audit': wfields.ObjectField('Audit', nullable=True),
|
||||||
'strategy': wfields.ObjectField('Strategy', nullable=True),
|
'strategy': wfields.ObjectField('Strategy', nullable=True),
|
||||||
|
|||||||
@@ -86,13 +86,15 @@ class Audit(base.WatcherPersistentObject, base.WatcherObject,
|
|||||||
# Version 1.2: Added 'auto_trigger' boolean field
|
# Version 1.2: Added 'auto_trigger' boolean field
|
||||||
# Version 1.3: Added 'next_run_time' DateTime field,
|
# Version 1.3: Added 'next_run_time' DateTime field,
|
||||||
# 'interval' type has been changed from Integer to String
|
# 'interval' type has been changed from Integer to String
|
||||||
VERSION = '1.3'
|
# Version 1.4: Added 'name' string field
|
||||||
|
VERSION = '1.4'
|
||||||
|
|
||||||
dbapi = db_api.get_instance()
|
dbapi = db_api.get_instance()
|
||||||
|
|
||||||
fields = {
|
fields = {
|
||||||
'id': wfields.IntegerField(),
|
'id': wfields.IntegerField(),
|
||||||
'uuid': wfields.UUIDField(),
|
'uuid': wfields.UUIDField(),
|
||||||
|
'name': wfields.StringField(),
|
||||||
'audit_type': wfields.StringField(),
|
'audit_type': wfields.StringField(),
|
||||||
'state': wfields.StringField(),
|
'state': wfields.StringField(),
|
||||||
'parameters': wfields.FlexibleDictField(nullable=True),
|
'parameters': wfields.FlexibleDictField(nullable=True),
|
||||||
@@ -204,6 +206,25 @@ class Audit(base.WatcherPersistentObject, base.WatcherObject,
|
|||||||
audit = cls._from_db_object(cls(context), db_audit, eager=eager)
|
audit = cls._from_db_object(cls(context), db_audit, eager=eager)
|
||||||
return audit
|
return audit
|
||||||
|
|
||||||
|
@base.remotable_classmethod
|
||||||
|
def get_by_name(cls, context, name, eager=False):
|
||||||
|
"""Find an audit based on name and return a :class:`Audit` object.
|
||||||
|
|
||||||
|
:param context: Security context. NOTE: This should only
|
||||||
|
be used internally by the indirection_api.
|
||||||
|
Unfortunately, RPC requires context as the first
|
||||||
|
argument, even though we don't use it.
|
||||||
|
A context should be set when instantiating the
|
||||||
|
object, e.g.: Audit(context)
|
||||||
|
:param name: the name of an audit.
|
||||||
|
:param eager: Load object fields if True (Default: False)
|
||||||
|
:returns: a :class:`Audit` object.
|
||||||
|
"""
|
||||||
|
|
||||||
|
db_audit = cls.dbapi.get_audit_by_name(context, name, eager=eager)
|
||||||
|
audit = cls._from_db_object(cls(context), db_audit, eager=eager)
|
||||||
|
return audit
|
||||||
|
|
||||||
@base.remotable_classmethod
|
@base.remotable_classmethod
|
||||||
def list(cls, context, limit=None, marker=None, filters=None,
|
def list(cls, context, limit=None, marker=None, filters=None,
|
||||||
sort_key=None, sort_dir=None, eager=False):
|
sort_key=None, sort_dir=None, eager=False):
|
||||||
|
|||||||
@@ -169,7 +169,8 @@ class TestListAction(api_base.FunctionalTest):
|
|||||||
action_list.append(action.uuid)
|
action_list.append(action.uuid)
|
||||||
|
|
||||||
audit2 = obj_utils.create_test_audit(
|
audit2 = obj_utils.create_test_audit(
|
||||||
self.context, id=2, uuid=utils.generate_uuid())
|
self.context, id=2, uuid=utils.generate_uuid(),
|
||||||
|
name='My Audit {0}'.format(2))
|
||||||
action_plan_2 = obj_utils.create_test_action_plan(
|
action_plan_2 = obj_utils.create_test_action_plan(
|
||||||
self.context,
|
self.context,
|
||||||
uuid=utils.generate_uuid(),
|
uuid=utils.generate_uuid(),
|
||||||
|
|||||||
@@ -128,12 +128,12 @@ class TestListActionPlan(api_base.FunctionalTest):
|
|||||||
|
|
||||||
def test_many_with_soft_deleted_audit_uuid(self):
|
def test_many_with_soft_deleted_audit_uuid(self):
|
||||||
action_plan_list = []
|
action_plan_list = []
|
||||||
audit1 = obj_utils.create_test_audit(self.context,
|
audit1 = obj_utils.create_test_audit(
|
||||||
id=2,
|
self.context, id=2,
|
||||||
uuid=utils.generate_uuid())
|
uuid=utils.generate_uuid(), name='My Audit {0}'.format(2))
|
||||||
audit2 = obj_utils.create_test_audit(self.context,
|
audit2 = obj_utils.create_test_audit(
|
||||||
id=3,
|
self.context, id=3,
|
||||||
uuid=utils.generate_uuid())
|
uuid=utils.generate_uuid(), name='My Audit {0}'.format(3))
|
||||||
|
|
||||||
for id_ in range(0, 2):
|
for id_ in range(0, 2):
|
||||||
action_plan = obj_utils.create_test_action_plan(
|
action_plan = obj_utils.create_test_action_plan(
|
||||||
@@ -163,9 +163,9 @@ class TestListActionPlan(api_base.FunctionalTest):
|
|||||||
|
|
||||||
def test_many_with_audit_uuid(self):
|
def test_many_with_audit_uuid(self):
|
||||||
action_plan_list = []
|
action_plan_list = []
|
||||||
audit = obj_utils.create_test_audit(self.context,
|
audit = obj_utils.create_test_audit(
|
||||||
id=2,
|
self.context, id=2,
|
||||||
uuid=utils.generate_uuid())
|
uuid=utils.generate_uuid(), name='My Audit {0}'.format(2))
|
||||||
for id_ in range(2, 5):
|
for id_ in range(2, 5):
|
||||||
action_plan = obj_utils.create_test_action_plan(
|
action_plan = obj_utils.create_test_action_plan(
|
||||||
self.context, id=id_, uuid=utils.generate_uuid(),
|
self.context, id=id_, uuid=utils.generate_uuid(),
|
||||||
@@ -178,18 +178,18 @@ class TestListActionPlan(api_base.FunctionalTest):
|
|||||||
|
|
||||||
def test_many_with_audit_uuid_filter(self):
|
def test_many_with_audit_uuid_filter(self):
|
||||||
action_plan_list1 = []
|
action_plan_list1 = []
|
||||||
audit1 = obj_utils.create_test_audit(self.context,
|
audit1 = obj_utils.create_test_audit(
|
||||||
id=2,
|
self.context, id=2,
|
||||||
uuid=utils.generate_uuid())
|
uuid=utils.generate_uuid(), name='My Audit {0}'.format(2))
|
||||||
for id_ in range(2, 5):
|
for id_ in range(2, 5):
|
||||||
action_plan = obj_utils.create_test_action_plan(
|
action_plan = obj_utils.create_test_action_plan(
|
||||||
self.context, id=id_, uuid=utils.generate_uuid(),
|
self.context, id=id_, uuid=utils.generate_uuid(),
|
||||||
audit_id=audit1.id)
|
audit_id=audit1.id)
|
||||||
action_plan_list1.append(action_plan.uuid)
|
action_plan_list1.append(action_plan.uuid)
|
||||||
|
|
||||||
audit2 = obj_utils.create_test_audit(self.context,
|
audit2 = obj_utils.create_test_audit(
|
||||||
id=3,
|
self.context, id=3,
|
||||||
uuid=utils.generate_uuid())
|
uuid=utils.generate_uuid(), name='My Audit {0}'.format(3))
|
||||||
action_plan_list2 = []
|
action_plan_list2 = []
|
||||||
for id_ in [5, 6, 7]:
|
for id_ in [5, 6, 7]:
|
||||||
action_plan = obj_utils.create_test_action_plan(
|
action_plan = obj_utils.create_test_action_plan(
|
||||||
@@ -237,9 +237,9 @@ class TestListActionPlan(api_base.FunctionalTest):
|
|||||||
def test_many_with_sort_key_audit_uuid(self):
|
def test_many_with_sort_key_audit_uuid(self):
|
||||||
audit_list = []
|
audit_list = []
|
||||||
for id_ in range(2, 5):
|
for id_ in range(2, 5):
|
||||||
audit = obj_utils.create_test_audit(self.context,
|
audit = obj_utils.create_test_audit(
|
||||||
id=id_,
|
self.context, id=id_,
|
||||||
uuid=utils.generate_uuid())
|
uuid=utils.generate_uuid(), name='My Audit {0}'.format(id_))
|
||||||
obj_utils.create_test_action_plan(
|
obj_utils.create_test_action_plan(
|
||||||
self.context, id=id_, uuid=utils.generate_uuid(),
|
self.context, id=id_, uuid=utils.generate_uuid(),
|
||||||
audit_id=audit.id)
|
audit_id=audit.id)
|
||||||
|
|||||||
@@ -512,18 +512,20 @@ class TestPost(FunctionalTestWithSetup):
|
|||||||
self.assertEqual(test_time, return_created_at)
|
self.assertEqual(test_time, return_created_at)
|
||||||
|
|
||||||
def test_create_audit_template_validation_with_aggregates(self):
|
def test_create_audit_template_validation_with_aggregates(self):
|
||||||
scope = [{'host_aggregates': [{'id': '*'}]},
|
scope = [{'compute': [{'host_aggregates': [{'id': '*'}]},
|
||||||
{'availability_zones': [{'name': 'AZ1'},
|
{'availability_zones': [{'name': 'AZ1'},
|
||||||
{'name': 'AZ2'}]},
|
{'name': 'AZ2'}]},
|
||||||
{'exclude': [
|
{'exclude': [
|
||||||
{'instances': [
|
{'instances': [
|
||||||
{'uuid': 'INSTANCE_1'},
|
{'uuid': 'INSTANCE_1'},
|
||||||
{'uuid': 'INSTANCE_2'}]},
|
{'uuid': 'INSTANCE_2'}]},
|
||||||
{'compute_nodes': [
|
{'compute_nodes': [
|
||||||
{'name': 'Node_1'},
|
{'name': 'Node_1'},
|
||||||
{'name': 'Node_2'}]},
|
{'name': 'Node_2'}]},
|
||||||
{'host_aggregates': [{'id': '*'}]}
|
{'host_aggregates': [{'id': '*'}]}
|
||||||
]}
|
]}
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
audit_template_dict = post_get_test_audit_template(
|
audit_template_dict = post_get_test_audit_template(
|
||||||
goal=self.fake_goal1.uuid,
|
goal=self.fake_goal1.uuid,
|
||||||
|
|||||||
@@ -154,8 +154,9 @@ class TestListAudit(api_base.FunctionalTest):
|
|||||||
def test_many(self):
|
def test_many(self):
|
||||||
audit_list = []
|
audit_list = []
|
||||||
for id_ in range(5):
|
for id_ in range(5):
|
||||||
audit = obj_utils.create_test_audit(self.context, id=id_,
|
audit = obj_utils.create_test_audit(
|
||||||
uuid=utils.generate_uuid())
|
self.context, id=id_,
|
||||||
|
uuid=utils.generate_uuid(), name='My Audit {0}'.format(id_))
|
||||||
audit_list.append(audit.uuid)
|
audit_list.append(audit.uuid)
|
||||||
response = self.get_json('/audits')
|
response = self.get_json('/audits')
|
||||||
self.assertEqual(len(audit_list), len(response['audits']))
|
self.assertEqual(len(audit_list), len(response['audits']))
|
||||||
@@ -165,12 +166,14 @@ class TestListAudit(api_base.FunctionalTest):
|
|||||||
def test_many_without_soft_deleted(self):
|
def test_many_without_soft_deleted(self):
|
||||||
audit_list = []
|
audit_list = []
|
||||||
for id_ in [1, 2, 3]:
|
for id_ in [1, 2, 3]:
|
||||||
audit = obj_utils.create_test_audit(self.context, id=id_,
|
audit = obj_utils.create_test_audit(
|
||||||
uuid=utils.generate_uuid())
|
self.context, id=id_,
|
||||||
|
uuid=utils.generate_uuid(), name='My Audit {0}'.format(id_))
|
||||||
audit_list.append(audit.uuid)
|
audit_list.append(audit.uuid)
|
||||||
for id_ in [4, 5]:
|
for id_ in [4, 5]:
|
||||||
audit = obj_utils.create_test_audit(self.context, id=id_,
|
audit = obj_utils.create_test_audit(
|
||||||
uuid=utils.generate_uuid())
|
self.context, id=id_,
|
||||||
|
uuid=utils.generate_uuid(), name='My Audit {0}'.format(id_))
|
||||||
audit.soft_delete()
|
audit.soft_delete()
|
||||||
response = self.get_json('/audits')
|
response = self.get_json('/audits')
|
||||||
self.assertEqual(3, len(response['audits']))
|
self.assertEqual(3, len(response['audits']))
|
||||||
@@ -180,12 +183,14 @@ class TestListAudit(api_base.FunctionalTest):
|
|||||||
def test_many_with_soft_deleted(self):
|
def test_many_with_soft_deleted(self):
|
||||||
audit_list = []
|
audit_list = []
|
||||||
for id_ in [1, 2, 3]:
|
for id_ in [1, 2, 3]:
|
||||||
audit = obj_utils.create_test_audit(self.context, id=id_,
|
audit = obj_utils.create_test_audit(
|
||||||
uuid=utils.generate_uuid())
|
self.context, id=id_,
|
||||||
|
uuid=utils.generate_uuid(), name='My Audit {0}'.format(id_))
|
||||||
audit_list.append(audit.uuid)
|
audit_list.append(audit.uuid)
|
||||||
for id_ in [4, 5]:
|
for id_ in [4, 5]:
|
||||||
audit = obj_utils.create_test_audit(self.context, id=id_,
|
audit = obj_utils.create_test_audit(
|
||||||
uuid=utils.generate_uuid())
|
self.context, id=id_,
|
||||||
|
uuid=utils.generate_uuid(), name='My Audit {0}'.format(id_))
|
||||||
audit.soft_delete()
|
audit.soft_delete()
|
||||||
audit_list.append(audit.uuid)
|
audit_list.append(audit.uuid)
|
||||||
response = self.get_json('/audits',
|
response = self.get_json('/audits',
|
||||||
@@ -203,7 +208,7 @@ class TestListAudit(api_base.FunctionalTest):
|
|||||||
uuid=utils.generate_uuid())
|
uuid=utils.generate_uuid())
|
||||||
obj_utils.create_test_audit(
|
obj_utils.create_test_audit(
|
||||||
self.context, id=id_, uuid=utils.generate_uuid(),
|
self.context, id=id_, uuid=utils.generate_uuid(),
|
||||||
goal_id=goal.id)
|
goal_id=goal.id, name='My Audit {0}'.format(id_))
|
||||||
goal_list.append(goal.uuid)
|
goal_list.append(goal.uuid)
|
||||||
|
|
||||||
response = self.get_json('/audits/?sort_key=goal_uuid')
|
response = self.get_json('/audits/?sort_key=goal_uuid')
|
||||||
@@ -214,7 +219,9 @@ class TestListAudit(api_base.FunctionalTest):
|
|||||||
|
|
||||||
def test_links(self):
|
def test_links(self):
|
||||||
uuid = utils.generate_uuid()
|
uuid = utils.generate_uuid()
|
||||||
obj_utils.create_test_audit(self.context, id=1, uuid=uuid)
|
obj_utils.create_test_audit(
|
||||||
|
self.context, id=1, uuid=uuid,
|
||||||
|
name='My Audit {0}'.format(1))
|
||||||
response = self.get_json('/audits/%s' % uuid)
|
response = self.get_json('/audits/%s' % uuid)
|
||||||
self.assertIn('links', response.keys())
|
self.assertIn('links', response.keys())
|
||||||
self.assertEqual(2, len(response['links']))
|
self.assertEqual(2, len(response['links']))
|
||||||
@@ -225,8 +232,9 @@ class TestListAudit(api_base.FunctionalTest):
|
|||||||
|
|
||||||
def test_collection_links(self):
|
def test_collection_links(self):
|
||||||
for id_ in range(5):
|
for id_ in range(5):
|
||||||
obj_utils.create_test_audit(self.context, id=id_,
|
obj_utils.create_test_audit(
|
||||||
uuid=utils.generate_uuid())
|
self.context, id=id_,
|
||||||
|
uuid=utils.generate_uuid(), name='My Audit {0}'.format(id_))
|
||||||
response = self.get_json('/audits/?limit=3')
|
response = self.get_json('/audits/?limit=3')
|
||||||
self.assertEqual(3, len(response['audits']))
|
self.assertEqual(3, len(response['audits']))
|
||||||
|
|
||||||
@@ -236,8 +244,9 @@ class TestListAudit(api_base.FunctionalTest):
|
|||||||
def test_collection_links_default_limit(self):
|
def test_collection_links_default_limit(self):
|
||||||
cfg.CONF.set_override('max_limit', 3, 'api')
|
cfg.CONF.set_override('max_limit', 3, 'api')
|
||||||
for id_ in range(5):
|
for id_ in range(5):
|
||||||
obj_utils.create_test_audit(self.context, id=id_,
|
obj_utils.create_test_audit(
|
||||||
uuid=utils.generate_uuid())
|
self.context, id=id_,
|
||||||
|
uuid=utils.generate_uuid(), name='My Audit {0}'.format(id_))
|
||||||
response = self.get_json('/audits')
|
response = self.get_json('/audits')
|
||||||
self.assertEqual(3, len(response['audits']))
|
self.assertEqual(3, len(response['audits']))
|
||||||
|
|
||||||
|
|||||||
@@ -110,18 +110,22 @@ class TestChangeNovaServiceState(base.TestCase):
|
|||||||
def test_execute_change_service_state_with_disable_target(self):
|
def test_execute_change_service_state_with_disable_target(self):
|
||||||
self.action.input_parameters["state"] = (
|
self.action.input_parameters["state"] = (
|
||||||
element.ServiceState.DISABLED.value)
|
element.ServiceState.DISABLED.value)
|
||||||
|
self.action.input_parameters["disabled_reason"] = (
|
||||||
|
"watcher_disabled")
|
||||||
self.action.execute()
|
self.action.execute()
|
||||||
|
|
||||||
self.m_helper_cls.assert_called_once_with(osc=self.m_osc)
|
self.m_helper_cls.assert_called_once_with(osc=self.m_osc)
|
||||||
self.m_helper.disable_service_nova_compute.assert_called_once_with(
|
self.m_helper.disable_service_nova_compute.assert_called_once_with(
|
||||||
"compute-1")
|
"compute-1", "watcher_disabled")
|
||||||
|
|
||||||
def test_revert_change_service_state_with_enable_target(self):
|
def test_revert_change_service_state_with_enable_target(self):
|
||||||
|
self.action.input_parameters["disabled_reason"] = (
|
||||||
|
"watcher_disabled")
|
||||||
self.action.revert()
|
self.action.revert()
|
||||||
|
|
||||||
self.m_helper_cls.assert_called_once_with(osc=self.m_osc)
|
self.m_helper_cls.assert_called_once_with(osc=self.m_osc)
|
||||||
self.m_helper.disable_service_nova_compute.assert_called_once_with(
|
self.m_helper.disable_service_nova_compute.assert_called_once_with(
|
||||||
"compute-1")
|
"compute-1", "watcher_disabled")
|
||||||
|
|
||||||
def test_revert_change_service_state_with_disable_target(self):
|
def test_revert_change_service_state_with_disable_target(self):
|
||||||
self.action.input_parameters["state"] = (
|
self.action.input_parameters["state"] = (
|
||||||
|
|||||||
@@ -210,34 +210,6 @@ class TestMigration(base.TestCase):
|
|||||||
dest_hostname="compute1-hostname"
|
dest_hostname="compute1-hostname"
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_live_migrate_non_shared_storage_instance(self):
|
|
||||||
self.m_helper.find_instance.return_value = self.INSTANCE_UUID
|
|
||||||
|
|
||||||
self.m_helper.live_migrate_instance.side_effect = [
|
|
||||||
nova_helper.nvexceptions.ClientException(400, "BadRequest"), True]
|
|
||||||
|
|
||||||
try:
|
|
||||||
self.action.execute()
|
|
||||||
except Exception as exc:
|
|
||||||
self.fail(exc)
|
|
||||||
|
|
||||||
self.m_helper.live_migrate_instance.assert_has_calls([
|
|
||||||
mock.call(instance_id=self.INSTANCE_UUID,
|
|
||||||
dest_hostname="compute2-hostname"),
|
|
||||||
mock.call(instance_id=self.INSTANCE_UUID,
|
|
||||||
dest_hostname="compute2-hostname",
|
|
||||||
block_migration=True)
|
|
||||||
])
|
|
||||||
|
|
||||||
expected = [mock.call.first(instance_id=self.INSTANCE_UUID,
|
|
||||||
dest_hostname="compute2-hostname"),
|
|
||||||
mock.call.second(instance_id=self.INSTANCE_UUID,
|
|
||||||
dest_hostname="compute2-hostname",
|
|
||||||
block_migration=True)
|
|
||||||
]
|
|
||||||
self.m_helper.live_migrate_instance.mock_calls == expected
|
|
||||||
self.assertEqual(2, self.m_helper.live_migrate_instance.call_count)
|
|
||||||
|
|
||||||
def test_abort_live_migrate(self):
|
def test_abort_live_migrate(self):
|
||||||
migration = mock.MagicMock()
|
migration = mock.MagicMock()
|
||||||
migration.id = "2"
|
migration.id = "2"
|
||||||
|
|||||||
@@ -165,6 +165,27 @@ class TestNovaHelper(base.TestCase):
|
|||||||
)
|
)
|
||||||
self.assertFalse(is_success)
|
self.assertFalse(is_success)
|
||||||
|
|
||||||
|
@mock.patch.object(time, 'sleep', mock.Mock())
|
||||||
|
def test_live_migrate_instance_with_task_state(
|
||||||
|
self, mock_glance, mock_cinder, mock_neutron, mock_nova):
|
||||||
|
nova_util = nova_helper.NovaHelper()
|
||||||
|
server = self.fake_server(self.instance_uuid)
|
||||||
|
setattr(server, 'OS-EXT-SRV-ATTR:host',
|
||||||
|
self.source_node)
|
||||||
|
setattr(server, 'OS-EXT-STS:task_state', '')
|
||||||
|
self.fake_nova_find_list(nova_util, find=server, list=None)
|
||||||
|
nova_util.live_migrate_instance(
|
||||||
|
self.instance_uuid, self.destination_node
|
||||||
|
)
|
||||||
|
time.sleep.assert_not_called()
|
||||||
|
|
||||||
|
setattr(server, 'OS-EXT-STS:task_state', 'migrating')
|
||||||
|
self.fake_nova_find_list(nova_util, find=server, list=server)
|
||||||
|
nova_util.live_migrate_instance(
|
||||||
|
self.instance_uuid, self.destination_node
|
||||||
|
)
|
||||||
|
time.sleep.assert_called_with(1)
|
||||||
|
|
||||||
@mock.patch.object(time, 'sleep', mock.Mock())
|
@mock.patch.object(time, 'sleep', mock.Mock())
|
||||||
def test_live_migrate_instance_no_destination_node(
|
def test_live_migrate_instance_no_destination_node(
|
||||||
self, mock_glance, mock_cinder, mock_neutron, mock_nova):
|
self, mock_glance, mock_cinder, mock_neutron, mock_nova):
|
||||||
@@ -328,13 +349,13 @@ class TestNovaHelper(base.TestCase):
|
|||||||
mock_neutron, mock_nova):
|
mock_neutron, mock_nova):
|
||||||
nova_util = nova_helper.NovaHelper()
|
nova_util = nova_helper.NovaHelper()
|
||||||
nova_services = nova_util.nova.services
|
nova_services = nova_util.nova.services
|
||||||
nova_services.disable.return_value = mock.MagicMock(
|
nova_services.disable_log_reason.return_value = mock.MagicMock(
|
||||||
status='enabled')
|
status='enabled')
|
||||||
|
|
||||||
result = nova_util.disable_service_nova_compute('nanjing')
|
result = nova_util.disable_service_nova_compute('nanjing')
|
||||||
self.assertFalse(result)
|
self.assertFalse(result)
|
||||||
|
|
||||||
nova_services.disable.return_value = mock.MagicMock(
|
nova_services.disable_log_reason.return_value = mock.MagicMock(
|
||||||
status='disabled')
|
status='disabled')
|
||||||
|
|
||||||
result = nova_util.disable_service_nova_compute('nanjing')
|
result = nova_util.disable_service_nova_compute('nanjing')
|
||||||
|
|||||||
@@ -38,25 +38,31 @@ class TestDbAuditFilters(base.DbTestCase):
|
|||||||
|
|
||||||
def _data_setup(self):
|
def _data_setup(self):
|
||||||
self.audit_template_name = "Audit Template"
|
self.audit_template_name = "Audit Template"
|
||||||
|
gen_name = lambda: "Audit %s" % w_utils.generate_uuid()
|
||||||
|
self.audit1_name = gen_name()
|
||||||
|
self.audit2_name = gen_name()
|
||||||
|
self.audit3_name = gen_name()
|
||||||
|
self.audit4_name = gen_name()
|
||||||
|
|
||||||
self.audit_template = utils.create_test_audit_template(
|
self.audit_template = utils.create_test_audit_template(
|
||||||
name=self.audit_template_name, id=1, uuid=None)
|
name=self.audit_template_name, id=1, uuid=None)
|
||||||
|
|
||||||
with freezegun.freeze_time(self.FAKE_TODAY):
|
with freezegun.freeze_time(self.FAKE_TODAY):
|
||||||
self.audit1 = utils.create_test_audit(
|
self.audit1 = utils.create_test_audit(
|
||||||
audit_template_id=self.audit_template.id, id=1, uuid=None)
|
audit_template_id=self.audit_template.id, id=1, uuid=None,
|
||||||
|
name=self.audit1_name)
|
||||||
with freezegun.freeze_time(self.FAKE_OLD_DATE):
|
with freezegun.freeze_time(self.FAKE_OLD_DATE):
|
||||||
self.audit2 = utils.create_test_audit(
|
self.audit2 = utils.create_test_audit(
|
||||||
audit_template_id=self.audit_template.id, id=2, uuid=None,
|
audit_template_id=self.audit_template.id, id=2, uuid=None,
|
||||||
state=objects.audit.State.FAILED)
|
name=self.audit2_name, state=objects.audit.State.FAILED)
|
||||||
with freezegun.freeze_time(self.FAKE_OLDER_DATE):
|
with freezegun.freeze_time(self.FAKE_OLDER_DATE):
|
||||||
self.audit3 = utils.create_test_audit(
|
self.audit3 = utils.create_test_audit(
|
||||||
audit_template_id=self.audit_template.id, id=3, uuid=None,
|
audit_template_id=self.audit_template.id, id=3, uuid=None,
|
||||||
state=objects.audit.State.CANCELLED)
|
name=self.audit3_name, state=objects.audit.State.CANCELLED)
|
||||||
with freezegun.freeze_time(self.FAKE_OLDER_DATE):
|
with freezegun.freeze_time(self.FAKE_OLDER_DATE):
|
||||||
self.audit4 = utils.create_test_audit(
|
self.audit4 = utils.create_test_audit(
|
||||||
audit_template_id=self.audit_template.id, id=4, uuid=None,
|
audit_template_id=self.audit_template.id, id=4, uuid=None,
|
||||||
state=objects.audit.State.SUSPENDED)
|
name=self.audit4_name, state=objects.audit.State.SUSPENDED)
|
||||||
|
|
||||||
def _soft_delete_audits(self):
|
def _soft_delete_audits(self):
|
||||||
with freezegun.freeze_time(self.FAKE_TODAY):
|
with freezegun.freeze_time(self.FAKE_TODAY):
|
||||||
@@ -266,8 +272,9 @@ class DbAuditTestCase(base.DbTestCase):
|
|||||||
|
|
||||||
def test_get_audit_list(self):
|
def test_get_audit_list(self):
|
||||||
uuids = []
|
uuids = []
|
||||||
for _ in range(1, 4):
|
for id_ in range(1, 4):
|
||||||
audit = utils.create_test_audit(uuid=w_utils.generate_uuid())
|
audit = utils.create_test_audit(uuid=w_utils.generate_uuid(),
|
||||||
|
name='My Audit {0}'.format(id_))
|
||||||
uuids.append(six.text_type(audit['uuid']))
|
uuids.append(six.text_type(audit['uuid']))
|
||||||
audits = self.dbapi.get_audit_list(self.context)
|
audits = self.dbapi.get_audit_list(self.context)
|
||||||
audit_uuids = [a.uuid for a in audits]
|
audit_uuids = [a.uuid for a in audits]
|
||||||
@@ -286,6 +293,7 @@ class DbAuditTestCase(base.DbTestCase):
|
|||||||
for i in range(1, 4):
|
for i in range(1, 4):
|
||||||
audit = utils.create_test_audit(
|
audit = utils.create_test_audit(
|
||||||
id=i, uuid=w_utils.generate_uuid(),
|
id=i, uuid=w_utils.generate_uuid(),
|
||||||
|
name='My Audit {0}'.format(i),
|
||||||
goal_id=goal.id, strategy_id=strategy.id)
|
goal_id=goal.id, strategy_id=strategy.id)
|
||||||
uuids.append(six.text_type(audit['uuid']))
|
uuids.append(six.text_type(audit['uuid']))
|
||||||
audits = self.dbapi.get_audit_list(self.context, eager=True)
|
audits = self.dbapi.get_audit_list(self.context, eager=True)
|
||||||
@@ -300,6 +308,7 @@ class DbAuditTestCase(base.DbTestCase):
|
|||||||
id=1,
|
id=1,
|
||||||
audit_type=objects.audit.AuditType.ONESHOT.value,
|
audit_type=objects.audit.AuditType.ONESHOT.value,
|
||||||
uuid=w_utils.generate_uuid(),
|
uuid=w_utils.generate_uuid(),
|
||||||
|
name='My Audit {0}'.format(1),
|
||||||
state=objects.audit.State.ONGOING)
|
state=objects.audit.State.ONGOING)
|
||||||
audit2 = self._create_test_audit(
|
audit2 = self._create_test_audit(
|
||||||
id=2,
|
id=2,
|
||||||
@@ -389,3 +398,21 @@ class DbAuditTestCase(base.DbTestCase):
|
|||||||
self.assertEqual(audit['id'], action_plan.audit_id)
|
self.assertEqual(audit['id'], action_plan.audit_id)
|
||||||
self.assertRaises(exception.AuditReferenced,
|
self.assertRaises(exception.AuditReferenced,
|
||||||
self.dbapi.destroy_audit, audit['id'])
|
self.dbapi.destroy_audit, audit['id'])
|
||||||
|
|
||||||
|
def test_create_audit_already_exists(self):
|
||||||
|
uuid = w_utils.generate_uuid()
|
||||||
|
self._create_test_audit(id=1, uuid=uuid)
|
||||||
|
self.assertRaises(exception.AuditAlreadyExists,
|
||||||
|
self._create_test_audit,
|
||||||
|
id=2, uuid=uuid)
|
||||||
|
|
||||||
|
def test_create_same_name_audit(self):
|
||||||
|
audit = utils.create_test_audit(
|
||||||
|
uuid=w_utils.generate_uuid(),
|
||||||
|
name='my_audit')
|
||||||
|
self.assertEqual(audit['uuid'], audit.uuid)
|
||||||
|
self.assertRaises(
|
||||||
|
exception.AuditAlreadyExists,
|
||||||
|
utils.create_test_audit,
|
||||||
|
uuid=w_utils.generate_uuid(),
|
||||||
|
name='my_audit')
|
||||||
|
|||||||
@@ -100,6 +100,13 @@ class TestPurgeCommand(base.DbTestCase):
|
|||||||
self.audit_template3_name = self.generate_unique_name(
|
self.audit_template3_name = self.generate_unique_name(
|
||||||
prefix="Audit Template 3 ")
|
prefix="Audit Template 3 ")
|
||||||
|
|
||||||
|
self.audit1_name = self.generate_unique_name(
|
||||||
|
prefix="Audit 1 ")
|
||||||
|
self.audit2_name = self.generate_unique_name(
|
||||||
|
prefix="Audit 2 ")
|
||||||
|
self.audit3_name = self.generate_unique_name(
|
||||||
|
prefix="Audit 3 ")
|
||||||
|
|
||||||
with freezegun.freeze_time(self.expired_date):
|
with freezegun.freeze_time(self.expired_date):
|
||||||
self.goal1 = obj_utils.create_test_goal(
|
self.goal1 = obj_utils.create_test_goal(
|
||||||
self.context, id=self._generate_id(),
|
self.context, id=self._generate_id(),
|
||||||
@@ -154,15 +161,15 @@ class TestPurgeCommand(base.DbTestCase):
|
|||||||
with freezegun.freeze_time(self.expired_date):
|
with freezegun.freeze_time(self.expired_date):
|
||||||
self.audit1 = obj_utils.create_test_audit(
|
self.audit1 = obj_utils.create_test_audit(
|
||||||
self.context, id=self._generate_id(),
|
self.context, id=self._generate_id(),
|
||||||
uuid=utils.generate_uuid(),
|
uuid=utils.generate_uuid(), name=self.audit1_name,
|
||||||
goal_id=self.goal1.id, strategy_id=self.strategy1.id)
|
goal_id=self.goal1.id, strategy_id=self.strategy1.id)
|
||||||
self.audit2 = obj_utils.create_test_audit(
|
self.audit2 = obj_utils.create_test_audit(
|
||||||
self.context, id=self._generate_id(),
|
self.context, id=self._generate_id(),
|
||||||
uuid=utils.generate_uuid(),
|
uuid=utils.generate_uuid(), name=self.audit2_name,
|
||||||
goal_id=self.goal2.id, strategy_id=self.strategy2.id)
|
goal_id=self.goal2.id, strategy_id=self.strategy2.id)
|
||||||
self.audit3 = obj_utils.create_test_audit(
|
self.audit3 = obj_utils.create_test_audit(
|
||||||
self.context, id=self._generate_id(),
|
self.context, id=self._generate_id(),
|
||||||
uuid=utils.generate_uuid(),
|
uuid=utils.generate_uuid(), name=self.audit3_name,
|
||||||
goal_id=self.goal3.id, strategy_id=self.strategy3.id)
|
goal_id=self.goal3.id, strategy_id=self.strategy3.id)
|
||||||
self.audit1.soft_delete()
|
self.audit1.soft_delete()
|
||||||
|
|
||||||
@@ -272,7 +279,8 @@ class TestPurgeCommand(base.DbTestCase):
|
|||||||
audit4 = obj_utils.create_test_audit(
|
audit4 = obj_utils.create_test_audit(
|
||||||
self.context, audit_template_id=audit_template4.id,
|
self.context, audit_template_id=audit_template4.id,
|
||||||
strategy_id=self.strategy1.id, id=self._generate_id(),
|
strategy_id=self.strategy1.id, id=self._generate_id(),
|
||||||
uuid=utils.generate_uuid())
|
uuid=utils.generate_uuid(),
|
||||||
|
name=self.generate_unique_name(prefix="Audit 4 "))
|
||||||
action_plan4 = obj_utils.create_test_action_plan(
|
action_plan4 = obj_utils.create_test_action_plan(
|
||||||
self.context,
|
self.context,
|
||||||
id=self._generate_id(), uuid=utils.generate_uuid(),
|
id=self._generate_id(), uuid=utils.generate_uuid(),
|
||||||
@@ -290,7 +298,8 @@ class TestPurgeCommand(base.DbTestCase):
|
|||||||
audit5 = obj_utils.create_test_audit(
|
audit5 = obj_utils.create_test_audit(
|
||||||
self.context, audit_template_id=audit_template5.id,
|
self.context, audit_template_id=audit_template5.id,
|
||||||
strategy_id=self.strategy1.id, id=self._generate_id(),
|
strategy_id=self.strategy1.id, id=self._generate_id(),
|
||||||
uuid=utils.generate_uuid())
|
uuid=utils.generate_uuid(),
|
||||||
|
name=self.generate_unique_name(prefix="Audit 5 "))
|
||||||
action_plan5 = obj_utils.create_test_action_plan(
|
action_plan5 = obj_utils.create_test_action_plan(
|
||||||
self.context,
|
self.context,
|
||||||
id=self._generate_id(), uuid=utils.generate_uuid(),
|
id=self._generate_id(), uuid=utils.generate_uuid(),
|
||||||
@@ -369,7 +378,8 @@ class TestPurgeCommand(base.DbTestCase):
|
|||||||
audit4 = obj_utils.create_test_audit(
|
audit4 = obj_utils.create_test_audit(
|
||||||
self.context,
|
self.context,
|
||||||
id=self._generate_id(), uuid=utils.generate_uuid(),
|
id=self._generate_id(), uuid=utils.generate_uuid(),
|
||||||
audit_template_id=audit_template4.id)
|
audit_template_id=audit_template4.id,
|
||||||
|
name=self.generate_unique_name(prefix="Audit 4 "))
|
||||||
action_plan4 = obj_utils.create_test_action_plan(
|
action_plan4 = obj_utils.create_test_action_plan(
|
||||||
self.context,
|
self.context,
|
||||||
id=self._generate_id(), uuid=utils.generate_uuid(),
|
id=self._generate_id(), uuid=utils.generate_uuid(),
|
||||||
@@ -387,7 +397,8 @@ class TestPurgeCommand(base.DbTestCase):
|
|||||||
audit5 = obj_utils.create_test_audit(
|
audit5 = obj_utils.create_test_audit(
|
||||||
self.context, audit_template_id=audit_template5.id,
|
self.context, audit_template_id=audit_template5.id,
|
||||||
strategy_id=self.strategy1.id, id=self._generate_id(),
|
strategy_id=self.strategy1.id, id=self._generate_id(),
|
||||||
uuid=utils.generate_uuid())
|
uuid=utils.generate_uuid(),
|
||||||
|
name=self.generate_unique_name(prefix="Audit 5 "))
|
||||||
action_plan5 = obj_utils.create_test_action_plan(
|
action_plan5 = obj_utils.create_test_action_plan(
|
||||||
self.context,
|
self.context,
|
||||||
id=self._generate_id(), uuid=utils.generate_uuid(),
|
id=self._generate_id(), uuid=utils.generate_uuid(),
|
||||||
|
|||||||
@@ -83,6 +83,7 @@ def get_test_audit(**kwargs):
|
|||||||
audit_data = {
|
audit_data = {
|
||||||
'id': kwargs.get('id', 1),
|
'id': kwargs.get('id', 1),
|
||||||
'uuid': kwargs.get('uuid', '10a47dd1-4874-4298-91cf-eff046dbdb8d'),
|
'uuid': kwargs.get('uuid', '10a47dd1-4874-4298-91cf-eff046dbdb8d'),
|
||||||
|
'name': kwargs.get('name', 'My Audit'),
|
||||||
'audit_type': kwargs.get('audit_type', 'ONESHOT'),
|
'audit_type': kwargs.get('audit_type', 'ONESHOT'),
|
||||||
'state': kwargs.get('state', objects.audit.State.PENDING),
|
'state': kwargs.get('state', objects.audit.State.PENDING),
|
||||||
'created_at': kwargs.get('created_at'),
|
'created_at': kwargs.get('created_at'),
|
||||||
@@ -166,7 +167,7 @@ def get_test_action_plan(**kwargs):
|
|||||||
'state': kwargs.get('state', objects.action_plan.State.ONGOING),
|
'state': kwargs.get('state', objects.action_plan.State.ONGOING),
|
||||||
'audit_id': kwargs.get('audit_id', 1),
|
'audit_id': kwargs.get('audit_id', 1),
|
||||||
'strategy_id': kwargs.get('strategy_id', 1),
|
'strategy_id': kwargs.get('strategy_id', 1),
|
||||||
'global_efficacy': kwargs.get('global_efficacy', {}),
|
'global_efficacy': kwargs.get('global_efficacy', []),
|
||||||
'created_at': kwargs.get('created_at'),
|
'created_at': kwargs.get('created_at'),
|
||||||
'updated_at': kwargs.get('updated_at'),
|
'updated_at': kwargs.get('updated_at'),
|
||||||
'deleted_at': kwargs.get('deleted_at'),
|
'deleted_at': kwargs.get('deleted_at'),
|
||||||
|
|||||||
@@ -232,6 +232,7 @@ class TestContinuousAuditHandler(base.DbTestCase):
|
|||||||
obj_utils.create_test_audit(
|
obj_utils.create_test_audit(
|
||||||
self.context,
|
self.context,
|
||||||
id=id_,
|
id=id_,
|
||||||
|
name='My Audit {0}'.format(id_),
|
||||||
uuid=uuidutils.generate_uuid(),
|
uuid=uuidutils.generate_uuid(),
|
||||||
audit_template_id=audit_template.id,
|
audit_template_id=audit_template.id,
|
||||||
goal_id=self.goal.id,
|
goal_id=self.goal.id,
|
||||||
@@ -376,7 +377,7 @@ class TestContinuousAuditHandler(base.DbTestCase):
|
|||||||
audit_handler = continuous.ContinuousAuditHandler()
|
audit_handler = continuous.ContinuousAuditHandler()
|
||||||
self.audits[0].next_run_time = (datetime.datetime.now() -
|
self.audits[0].next_run_time = (datetime.datetime.now() -
|
||||||
datetime.timedelta(seconds=1800))
|
datetime.timedelta(seconds=1800))
|
||||||
m_is_inactive.return_value = True
|
m_is_inactive.return_value = False
|
||||||
m_get_jobs.return_value = None
|
m_get_jobs.return_value = None
|
||||||
|
|
||||||
audit_handler.execute_audit(self.audits[0], self.context)
|
audit_handler.execute_audit(self.audits[0], self.context)
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user