|
|
f778fe |
From db1a118ed0d36633c67513961b479f8fae3cc2b9 Mon Sep 17 00:00:00 2001
|
|
|
f778fe |
From: Ivan Devat <idevat@redhat.com>
|
|
|
f778fe |
Date: Thu, 15 Jun 2017 11:46:12 +0200
|
|
|
f778fe |
Subject: [PATCH] squash bz1447910 bundle resources are missing meta
|
|
|
f778fe |
|
|
|
f778fe |
d21dd0e6b4d3 make resource enable | disable work with bundles
|
|
|
f778fe |
|
|
|
f778fe |
27d46c115210 make resource manage | unmanage work with bundles
|
|
|
f778fe |
|
|
|
f778fe |
c963cdcd321b show bundles' meta attributes in resources listing
|
|
|
f778fe |
|
|
|
f778fe |
f1923af76d73 support meta attributes in 'resource bundle create'
|
|
|
f778fe |
|
|
|
f778fe |
e09015ee868a support meta attributes in 'resource bundle update'
|
|
|
f778fe |
|
|
|
f778fe |
c6e70a38346a stop bundles when deleting them
|
|
|
f778fe |
---
|
|
|
f778fe |
pcs/cli/resource/parse_args.py | 4 +-
|
|
|
f778fe |
pcs/cli/resource/test/test_parse_args.py | 70 ++++++++
|
|
|
f778fe |
pcs/lib/cib/nvpair.py | 12 +-
|
|
|
f778fe |
pcs/lib/cib/resource/bundle.py | 17 +-
|
|
|
f778fe |
pcs/lib/cib/resource/common.py | 40 +++--
|
|
|
f778fe |
pcs/lib/cib/test/test_nvpair.py | 42 +++++
|
|
|
f778fe |
pcs/lib/cib/test/test_resource_common.py | 16 +-
|
|
|
f778fe |
pcs/lib/cib/tools.py | 10 +-
|
|
|
f778fe |
pcs/lib/commands/resource.py | 86 +++++++---
|
|
|
f778fe |
pcs/lib/commands/test/resource/fixture.py | 2 +-
|
|
|
f778fe |
.../commands/test/resource/test_bundle_create.py | 179 +++++++++++++++----
|
|
|
f778fe |
.../commands/test/resource/test_bundle_update.py | 102 ++++++++++-
|
|
|
f778fe |
.../test/resource/test_resource_enable_disable.py | 93 ++++++++--
|
|
|
f778fe |
.../test/resource/test_resource_manage_unmanage.py | 189 +++++++++++++++++++--
|
|
|
f778fe |
pcs/lib/pacemaker/state.py | 40 ++++-
|
|
|
f778fe |
pcs/lib/pacemaker/test/test_state.py | 108 +++++++++++-
|
|
|
f778fe |
pcs/pcs.8 | 6 +-
|
|
|
f778fe |
pcs/resource.py | 99 ++++++++---
|
|
|
f778fe |
pcs/test/cib_resource/test_bundle.py | 67 ++++++++
|
|
|
f778fe |
pcs/test/cib_resource/test_manage_unmanage.py | 5 +-
|
|
|
f778fe |
pcs/test/test_resource.py | 40 +++--
|
|
|
f778fe |
pcs/usage.py | 9 +-
|
|
|
f778fe |
22 files changed, 1055 insertions(+), 181 deletions(-)
|
|
|
f778fe |
|
|
|
f778fe |
diff --git a/pcs/cli/resource/parse_args.py b/pcs/cli/resource/parse_args.py
|
|
|
f778fe |
index 19ee8f9..366acac 100644
|
|
|
f778fe |
--- a/pcs/cli/resource/parse_args.py
|
|
|
f778fe |
+++ b/pcs/cli/resource/parse_args.py
|
|
|
f778fe |
@@ -58,7 +58,7 @@ def parse_create(arg_list):
|
|
|
f778fe |
|
|
|
f778fe |
def _parse_bundle_groups(arg_list):
|
|
|
f778fe |
repeatable_keyword_list = ["port-map", "storage-map"]
|
|
|
f778fe |
- keyword_list = ["container", "network"] + repeatable_keyword_list
|
|
|
f778fe |
+ keyword_list = ["meta", "container", "network"] + repeatable_keyword_list
|
|
|
f778fe |
groups = group_by_keywords(
|
|
|
f778fe |
arg_list,
|
|
|
f778fe |
set(keyword_list),
|
|
|
f778fe |
@@ -99,6 +99,7 @@ def parse_bundle_create_options(arg_list):
|
|
|
f778fe |
prepare_options(storage_map)
|
|
|
f778fe |
for storage_map in groups.get("storage-map", [])
|
|
|
f778fe |
],
|
|
|
f778fe |
+ "meta": prepare_options(groups.get("meta", []))
|
|
|
f778fe |
}
|
|
|
f778fe |
if not parts["container_type"]:
|
|
|
f778fe |
parts["container_type"] = "docker"
|
|
|
f778fe |
@@ -144,6 +145,7 @@ def parse_bundle_update_options(arg_list):
|
|
|
f778fe |
"port_map_remove": port_map["remove"],
|
|
|
f778fe |
"storage_map_add": storage_map["add"],
|
|
|
f778fe |
"storage_map_remove": storage_map["remove"],
|
|
|
f778fe |
+ "meta": prepare_options(groups.get("meta", []))
|
|
|
f778fe |
}
|
|
|
f778fe |
return parts
|
|
|
f778fe |
|
|
|
f778fe |
diff --git a/pcs/cli/resource/test/test_parse_args.py b/pcs/cli/resource/test/test_parse_args.py
|
|
|
f778fe |
index 5033ec7..0c936cc 100644
|
|
|
f778fe |
--- a/pcs/cli/resource/test/test_parse_args.py
|
|
|
f778fe |
+++ b/pcs/cli/resource/test/test_parse_args.py
|
|
|
f778fe |
@@ -220,6 +220,7 @@ class ParseBundleCreateOptions(TestCase):
|
|
|
f778fe |
"network": {},
|
|
|
f778fe |
"port_map": [],
|
|
|
f778fe |
"storage_map": [],
|
|
|
f778fe |
+ "meta": {},
|
|
|
f778fe |
}
|
|
|
f778fe |
)
|
|
|
f778fe |
|
|
|
f778fe |
@@ -235,6 +236,7 @@ class ParseBundleCreateOptions(TestCase):
|
|
|
f778fe |
"network": {},
|
|
|
f778fe |
"port_map": [],
|
|
|
f778fe |
"storage_map": [],
|
|
|
f778fe |
+ "meta": {},
|
|
|
f778fe |
}
|
|
|
f778fe |
)
|
|
|
f778fe |
|
|
|
f778fe |
@@ -247,6 +249,7 @@ class ParseBundleCreateOptions(TestCase):
|
|
|
f778fe |
"network": {},
|
|
|
f778fe |
"port_map": [],
|
|
|
f778fe |
"storage_map": [],
|
|
|
f778fe |
+ "meta": {},
|
|
|
f778fe |
}
|
|
|
f778fe |
)
|
|
|
f778fe |
|
|
|
f778fe |
@@ -259,6 +262,7 @@ class ParseBundleCreateOptions(TestCase):
|
|
|
f778fe |
"network": {},
|
|
|
f778fe |
"port_map": [],
|
|
|
f778fe |
"storage_map": [],
|
|
|
f778fe |
+ "meta": {},
|
|
|
f778fe |
}
|
|
|
f778fe |
)
|
|
|
f778fe |
|
|
|
f778fe |
@@ -280,6 +284,7 @@ class ParseBundleCreateOptions(TestCase):
|
|
|
f778fe |
"network": {"a": "b", "c": "d"},
|
|
|
f778fe |
"port_map": [],
|
|
|
f778fe |
"storage_map": [],
|
|
|
f778fe |
+ "meta": {},
|
|
|
f778fe |
}
|
|
|
f778fe |
)
|
|
|
f778fe |
|
|
|
f778fe |
@@ -309,6 +314,7 @@ class ParseBundleCreateOptions(TestCase):
|
|
|
f778fe |
"network": {},
|
|
|
f778fe |
"port_map": [{"a": "b", "c": "d"}],
|
|
|
f778fe |
"storage_map": [],
|
|
|
f778fe |
+ "meta": {},
|
|
|
f778fe |
}
|
|
|
f778fe |
)
|
|
|
f778fe |
|
|
|
f778fe |
@@ -321,6 +327,7 @@ class ParseBundleCreateOptions(TestCase):
|
|
|
f778fe |
"network": {},
|
|
|
f778fe |
"port_map": [{"a": "b", "c": "d"}, {"e": "f"}],
|
|
|
f778fe |
"storage_map": [],
|
|
|
f778fe |
+ "meta": {},
|
|
|
f778fe |
}
|
|
|
f778fe |
)
|
|
|
f778fe |
|
|
|
f778fe |
@@ -347,6 +354,7 @@ class ParseBundleCreateOptions(TestCase):
|
|
|
f778fe |
"network": {},
|
|
|
f778fe |
"port_map": [],
|
|
|
f778fe |
"storage_map": [{"a": "b", "c": "d"}],
|
|
|
f778fe |
+ "meta": {},
|
|
|
f778fe |
}
|
|
|
f778fe |
)
|
|
|
f778fe |
|
|
|
f778fe |
@@ -359,6 +367,7 @@ class ParseBundleCreateOptions(TestCase):
|
|
|
f778fe |
"network": {},
|
|
|
f778fe |
"port_map": [],
|
|
|
f778fe |
"storage_map": [{"a": "b", "c": "d"}, {"e": "f"}],
|
|
|
f778fe |
+ "meta": {},
|
|
|
f778fe |
}
|
|
|
f778fe |
)
|
|
|
f778fe |
|
|
|
f778fe |
@@ -368,6 +377,28 @@ class ParseBundleCreateOptions(TestCase):
|
|
|
f778fe |
def test_storage_map_missing_key(self):
|
|
|
f778fe |
self.assert_raises_cmdline(["storage-map", "=b", "c=d"])
|
|
|
f778fe |
|
|
|
f778fe |
+ def test_meta(self):
|
|
|
f778fe |
+ self.assert_produce(
|
|
|
f778fe |
+ ["meta", "a=b", "c=d"],
|
|
|
f778fe |
+ {
|
|
|
f778fe |
+ "container_type": "docker",
|
|
|
f778fe |
+ "container": {},
|
|
|
f778fe |
+ "network": {},
|
|
|
f778fe |
+ "port_map": [],
|
|
|
f778fe |
+ "storage_map": [],
|
|
|
f778fe |
+ "meta": {"a": "b", "c": "d"},
|
|
|
f778fe |
+ }
|
|
|
f778fe |
+ )
|
|
|
f778fe |
+
|
|
|
f778fe |
+ def test_meta_empty(self):
|
|
|
f778fe |
+ self.assert_raises_cmdline(["meta"])
|
|
|
f778fe |
+
|
|
|
f778fe |
+ def test_meta_missing_value(self):
|
|
|
f778fe |
+ self.assert_raises_cmdline(["meta", "a", "c=d"])
|
|
|
f778fe |
+
|
|
|
f778fe |
+ def test_meta_missing_key(self):
|
|
|
f778fe |
+ self.assert_raises_cmdline(["meta", "=b", "c=d"])
|
|
|
f778fe |
+
|
|
|
f778fe |
def test_all(self):
|
|
|
f778fe |
self.assert_produce(
|
|
|
f778fe |
[
|
|
|
f778fe |
@@ -377,6 +408,7 @@ class ParseBundleCreateOptions(TestCase):
|
|
|
f778fe |
"port-map", "m=n", "o=p",
|
|
|
f778fe |
"storage-map", "q=r", "s=t",
|
|
|
f778fe |
"storage-map", "u=v", "w=x",
|
|
|
f778fe |
+ "meta", "y=z", "A=B",
|
|
|
f778fe |
],
|
|
|
f778fe |
{
|
|
|
f778fe |
"container_type": "lxc",
|
|
|
f778fe |
@@ -384,6 +416,7 @@ class ParseBundleCreateOptions(TestCase):
|
|
|
f778fe |
"network": {"e": "f", "g": "h"},
|
|
|
f778fe |
"port_map": [{"i": "j", "k": "l"}, {"m": "n", "o": "p"}],
|
|
|
f778fe |
"storage_map": [{"q": "r", "s": "t"}, {"u": "v", "w": "x"}],
|
|
|
f778fe |
+ "meta": {"y": "z", "A": "B"},
|
|
|
f778fe |
}
|
|
|
f778fe |
)
|
|
|
f778fe |
|
|
|
f778fe |
@@ -391,11 +424,13 @@ class ParseBundleCreateOptions(TestCase):
|
|
|
f778fe |
self.assert_produce(
|
|
|
f778fe |
[
|
|
|
f778fe |
"storage-map", "q=r", "s=t",
|
|
|
f778fe |
+ "meta", "y=z",
|
|
|
f778fe |
"port-map", "i=j", "k=l",
|
|
|
f778fe |
"network", "e=f",
|
|
|
f778fe |
"container", "lxc", "a=b",
|
|
|
f778fe |
"storage-map", "u=v", "w=x",
|
|
|
f778fe |
"port-map", "m=n", "o=p",
|
|
|
f778fe |
+ "meta", "A=B",
|
|
|
f778fe |
"network", "g=h",
|
|
|
f778fe |
"container", "c=d",
|
|
|
f778fe |
],
|
|
|
f778fe |
@@ -405,6 +440,7 @@ class ParseBundleCreateOptions(TestCase):
|
|
|
f778fe |
"network": {"e": "f", "g": "h"},
|
|
|
f778fe |
"port_map": [{"i": "j", "k": "l"}, {"m": "n", "o": "p"}],
|
|
|
f778fe |
"storage_map": [{"q": "r", "s": "t"}, {"u": "v", "w": "x"}],
|
|
|
f778fe |
+ "meta": {"y": "z", "A": "B"},
|
|
|
f778fe |
}
|
|
|
f778fe |
)
|
|
|
f778fe |
|
|
|
f778fe |
@@ -432,6 +468,7 @@ class ParseBundleUpdateOptions(TestCase):
|
|
|
f778fe |
"port_map_remove": [],
|
|
|
f778fe |
"storage_map_add": [],
|
|
|
f778fe |
"storage_map_remove": [],
|
|
|
f778fe |
+ "meta": {},
|
|
|
f778fe |
}
|
|
|
f778fe |
)
|
|
|
f778fe |
|
|
|
f778fe |
@@ -445,6 +482,7 @@ class ParseBundleUpdateOptions(TestCase):
|
|
|
f778fe |
"port_map_remove": [],
|
|
|
f778fe |
"storage_map_add": [],
|
|
|
f778fe |
"storage_map_remove": [],
|
|
|
f778fe |
+ "meta": {},
|
|
|
f778fe |
}
|
|
|
f778fe |
)
|
|
|
f778fe |
|
|
|
f778fe |
@@ -467,6 +505,7 @@ class ParseBundleUpdateOptions(TestCase):
|
|
|
f778fe |
"port_map_remove": [],
|
|
|
f778fe |
"storage_map_add": [],
|
|
|
f778fe |
"storage_map_remove": [],
|
|
|
f778fe |
+ "meta": {},
|
|
|
f778fe |
}
|
|
|
f778fe |
)
|
|
|
f778fe |
|
|
|
f778fe |
@@ -519,6 +558,7 @@ class ParseBundleUpdateOptions(TestCase):
|
|
|
f778fe |
"port_map_remove": ["c", "d", "i"],
|
|
|
f778fe |
"storage_map_add": [],
|
|
|
f778fe |
"storage_map_remove": [],
|
|
|
f778fe |
+ "meta": {},
|
|
|
f778fe |
}
|
|
|
f778fe |
)
|
|
|
f778fe |
|
|
|
f778fe |
@@ -562,9 +602,34 @@ class ParseBundleUpdateOptions(TestCase):
|
|
|
f778fe |
{"e": "f", "g": "h",},
|
|
|
f778fe |
],
|
|
|
f778fe |
"storage_map_remove": ["c", "d", "i"],
|
|
|
f778fe |
+ "meta": {},
|
|
|
f778fe |
+ }
|
|
|
f778fe |
+ )
|
|
|
f778fe |
+
|
|
|
f778fe |
+ def test_meta(self):
|
|
|
f778fe |
+ self.assert_produce(
|
|
|
f778fe |
+ ["meta", "a=b", "c=d"],
|
|
|
f778fe |
+ {
|
|
|
f778fe |
+ "container": {},
|
|
|
f778fe |
+ "network": {},
|
|
|
f778fe |
+ "port_map_add": [],
|
|
|
f778fe |
+ "port_map_remove": [],
|
|
|
f778fe |
+ "storage_map_add": [],
|
|
|
f778fe |
+ "storage_map_remove": [],
|
|
|
f778fe |
+ "meta": {"a": "b", "c": "d"},
|
|
|
f778fe |
}
|
|
|
f778fe |
)
|
|
|
f778fe |
|
|
|
f778fe |
+ def test_meta_empty(self):
|
|
|
f778fe |
+ self.assert_raises_cmdline(["meta"])
|
|
|
f778fe |
+
|
|
|
f778fe |
+ def test_meta_missing_value(self):
|
|
|
f778fe |
+ self.assert_raises_cmdline(["meta", "a", "c=d"])
|
|
|
f778fe |
+
|
|
|
f778fe |
+ def test_meta_missing_key(self):
|
|
|
f778fe |
+ self.assert_raises_cmdline(["meta", "=b", "c=d"])
|
|
|
f778fe |
+
|
|
|
f778fe |
+
|
|
|
f778fe |
def test_all(self):
|
|
|
f778fe |
self.assert_produce(
|
|
|
f778fe |
[
|
|
|
f778fe |
@@ -578,6 +643,7 @@ class ParseBundleUpdateOptions(TestCase):
|
|
|
f778fe |
"storage-map", "add", "v=w",
|
|
|
f778fe |
"storage-map", "remove", "x", "y",
|
|
|
f778fe |
"storage-map", "remove", "z",
|
|
|
f778fe |
+ "meta", "A=B", "C=D",
|
|
|
f778fe |
],
|
|
|
f778fe |
{
|
|
|
f778fe |
"container": {"a": "b", "c": "d"},
|
|
|
f778fe |
@@ -592,6 +658,7 @@ class ParseBundleUpdateOptions(TestCase):
|
|
|
f778fe |
{"v": "w"},
|
|
|
f778fe |
],
|
|
|
f778fe |
"storage_map_remove": ["x", "y", "z"],
|
|
|
f778fe |
+ "meta": {"A": "B", "C": "D"},
|
|
|
f778fe |
}
|
|
|
f778fe |
)
|
|
|
f778fe |
|
|
|
f778fe |
@@ -599,11 +666,13 @@ class ParseBundleUpdateOptions(TestCase):
|
|
|
f778fe |
self.assert_produce(
|
|
|
f778fe |
[
|
|
|
f778fe |
"storage-map", "remove", "x", "y",
|
|
|
f778fe |
+ "meta", "A=B",
|
|
|
f778fe |
"port-map", "remove", "o", "p",
|
|
|
f778fe |
"network", "e=f", "g=h",
|
|
|
f778fe |
"storage-map", "add", "r=s", "t=u",
|
|
|
f778fe |
"port-map", "add", "i=j", "k=l",
|
|
|
f778fe |
"container", "a=b", "c=d",
|
|
|
f778fe |
+ "meta", "C=D",
|
|
|
f778fe |
"port-map", "remove", "q",
|
|
|
f778fe |
"storage-map", "remove", "z",
|
|
|
f778fe |
"storage-map", "add", "v=w",
|
|
|
f778fe |
@@ -622,6 +691,7 @@ class ParseBundleUpdateOptions(TestCase):
|
|
|
f778fe |
{"v": "w"},
|
|
|
f778fe |
],
|
|
|
f778fe |
"storage_map_remove": ["x", "y", "z"],
|
|
|
f778fe |
+ "meta": {"A": "B", "C": "D"},
|
|
|
f778fe |
}
|
|
|
f778fe |
)
|
|
|
f778fe |
|
|
|
f778fe |
diff --git a/pcs/lib/cib/nvpair.py b/pcs/lib/cib/nvpair.py
|
|
|
f778fe |
index 261d17c..d3f5a5c 100644
|
|
|
f778fe |
--- a/pcs/lib/cib/nvpair.py
|
|
|
f778fe |
+++ b/pcs/lib/cib/nvpair.py
|
|
|
f778fe |
@@ -11,18 +11,19 @@ from functools import partial
|
|
|
f778fe |
from pcs.lib.cib.tools import create_subelement_id
|
|
|
f778fe |
from pcs.lib.xml_tools import get_sub_element
|
|
|
f778fe |
|
|
|
f778fe |
-def _append_new_nvpair(nvset_element, name, value):
|
|
|
f778fe |
+def _append_new_nvpair(nvset_element, name, value, id_provider=None):
|
|
|
f778fe |
"""
|
|
|
f778fe |
Create nvpair with name and value as subelement of nvset_element.
|
|
|
f778fe |
|
|
|
f778fe |
etree.Element nvset_element is context of new nvpair
|
|
|
f778fe |
string name is name attribute of new nvpair
|
|
|
f778fe |
string value is value attribute of new nvpair
|
|
|
f778fe |
+ IdProvider id_provider -- elements' ids generator
|
|
|
f778fe |
"""
|
|
|
f778fe |
etree.SubElement(
|
|
|
f778fe |
nvset_element,
|
|
|
f778fe |
"nvpair",
|
|
|
f778fe |
- id=create_subelement_id(nvset_element, name),
|
|
|
f778fe |
+ id=create_subelement_id(nvset_element, name, id_provider),
|
|
|
f778fe |
name=name,
|
|
|
f778fe |
value=value
|
|
|
f778fe |
)
|
|
|
f778fe |
@@ -73,7 +74,7 @@ def arrange_first_nvset(tag_name, context_element, nvpair_dict):
|
|
|
f778fe |
|
|
|
f778fe |
update_nvset(nvset_element, nvpair_dict)
|
|
|
f778fe |
|
|
|
f778fe |
-def append_new_nvset(tag_name, context_element, nvpair_dict):
|
|
|
f778fe |
+def append_new_nvset(tag_name, context_element, nvpair_dict, id_provider=None):
|
|
|
f778fe |
"""
|
|
|
f778fe |
Append new nvset_element comprising nvpairs children (corresponding
|
|
|
f778fe |
nvpair_dict) to the context_element
|
|
|
f778fe |
@@ -81,12 +82,13 @@ def append_new_nvset(tag_name, context_element, nvpair_dict):
|
|
|
f778fe |
string tag_name should be "instance_attributes" or "meta_attributes"
|
|
|
f778fe |
etree.Element context_element is element where new nvset will be appended
|
|
|
f778fe |
dict nvpair_dict contains source for nvpair children
|
|
|
f778fe |
+ IdProvider id_provider -- elements' ids generator
|
|
|
f778fe |
"""
|
|
|
f778fe |
nvset_element = etree.SubElement(context_element, tag_name, {
|
|
|
f778fe |
- "id": create_subelement_id(context_element, tag_name)
|
|
|
f778fe |
+ "id": create_subelement_id(context_element, tag_name, id_provider)
|
|
|
f778fe |
})
|
|
|
f778fe |
for name, value in sorted(nvpair_dict.items()):
|
|
|
f778fe |
- _append_new_nvpair(nvset_element, name, value)
|
|
|
f778fe |
+ _append_new_nvpair(nvset_element, name, value, id_provider)
|
|
|
f778fe |
|
|
|
f778fe |
append_new_instance_attributes = partial(
|
|
|
f778fe |
append_new_nvset,
|
|
|
f778fe |
diff --git a/pcs/lib/cib/resource/bundle.py b/pcs/lib/cib/resource/bundle.py
|
|
|
f778fe |
index 0fe16f3..8a49c28 100644
|
|
|
f778fe |
--- a/pcs/lib/cib/resource/bundle.py
|
|
|
f778fe |
+++ b/pcs/lib/cib/resource/bundle.py
|
|
|
f778fe |
@@ -9,6 +9,10 @@ from lxml import etree
|
|
|
f778fe |
|
|
|
f778fe |
from pcs.common import report_codes
|
|
|
f778fe |
from pcs.lib import reports, validate
|
|
|
f778fe |
+from pcs.lib.cib.nvpair import (
|
|
|
f778fe |
+ append_new_meta_attributes,
|
|
|
f778fe |
+ arrange_first_meta_attributes,
|
|
|
f778fe |
+)
|
|
|
f778fe |
from pcs.lib.cib.resource.primitive import TAG as TAG_PRIMITIVE
|
|
|
f778fe |
from pcs.lib.cib.tools import find_element_by_tag_and_id
|
|
|
f778fe |
from pcs.lib.errors import (
|
|
|
f778fe |
@@ -96,7 +100,7 @@ def validate_new(
|
|
|
f778fe |
|
|
|
f778fe |
def append_new(
|
|
|
f778fe |
parent_element, id_provider, bundle_id, container_type, container_options,
|
|
|
f778fe |
- network_options, port_map, storage_map
|
|
|
f778fe |
+ network_options, port_map, storage_map, meta_attributes
|
|
|
f778fe |
):
|
|
|
f778fe |
"""
|
|
|
f778fe |
Create new bundle and add it to the CIB
|
|
|
f778fe |
@@ -109,6 +113,7 @@ def append_new(
|
|
|
f778fe |
dict network_options -- network options
|
|
|
f778fe |
list of dict port_map -- list of port mapping options
|
|
|
f778fe |
list of dict storage_map -- list of storage mapping options
|
|
|
f778fe |
+ dict meta_attributes -- meta attributes
|
|
|
f778fe |
"""
|
|
|
f778fe |
bundle_element = etree.SubElement(parent_element, TAG, {"id": bundle_id})
|
|
|
f778fe |
# TODO create the proper element once more container_types are supported
|
|
|
f778fe |
@@ -132,6 +137,8 @@ def append_new(
|
|
|
f778fe |
_append_storage_map(
|
|
|
f778fe |
storage_element, id_provider, bundle_id, storage_map_options
|
|
|
f778fe |
)
|
|
|
f778fe |
+ if meta_attributes:
|
|
|
f778fe |
+ append_new_meta_attributes(bundle_element, meta_attributes, id_provider)
|
|
|
f778fe |
return bundle_element
|
|
|
f778fe |
|
|
|
f778fe |
def validate_update(
|
|
|
f778fe |
@@ -203,7 +210,8 @@ def validate_update(
|
|
|
f778fe |
|
|
|
f778fe |
def update(
|
|
|
f778fe |
id_provider, bundle_el, container_options, network_options,
|
|
|
f778fe |
- port_map_add, port_map_remove, storage_map_add, storage_map_remove
|
|
|
f778fe |
+ port_map_add, port_map_remove, storage_map_add, storage_map_remove,
|
|
|
f778fe |
+ meta_attributes
|
|
|
f778fe |
):
|
|
|
f778fe |
"""
|
|
|
f778fe |
Modify an existing bundle (does not touch encapsulated resources)
|
|
|
f778fe |
@@ -216,6 +224,7 @@ def update(
|
|
|
f778fe |
list of string port_map_remove -- list of port mapping ids to remove
|
|
|
f778fe |
list of dict storage_map_add -- list of storage mapping options to add
|
|
|
f778fe |
list of string storage_map_remove -- list of storage mapping ids to remove
|
|
|
f778fe |
+ dict meta_attributes -- meta attributes to update
|
|
|
f778fe |
"""
|
|
|
f778fe |
bundle_id = bundle_el.get("id")
|
|
|
f778fe |
update_attributes_remove_empty(
|
|
|
f778fe |
@@ -253,7 +262,11 @@ def update(
|
|
|
f778fe |
storage_element, id_provider, bundle_id, storage_map_options
|
|
|
f778fe |
)
|
|
|
f778fe |
|
|
|
f778fe |
+ if meta_attributes:
|
|
|
f778fe |
+ arrange_first_meta_attributes(bundle_el, meta_attributes)
|
|
|
f778fe |
+
|
|
|
f778fe |
# remove empty elements with no attributes
|
|
|
f778fe |
+ # meta attributes are handled in their own function
|
|
|
f778fe |
for element in (network_element, storage_element):
|
|
|
f778fe |
if len(element) < 1 and not element.attrib:
|
|
|
f778fe |
element.getparent().remove(element)
|
|
|
f778fe |
diff --git a/pcs/lib/cib/resource/common.py b/pcs/lib/cib/resource/common.py
|
|
|
f778fe |
index f9028ff..0e52b4c 100644
|
|
|
f778fe |
--- a/pcs/lib/cib/resource/common.py
|
|
|
f778fe |
+++ b/pcs/lib/cib/resource/common.py
|
|
|
f778fe |
@@ -58,16 +58,18 @@ def find_resources_to_enable(resource_el):
|
|
|
f778fe |
etree resource_el -- resource element
|
|
|
f778fe |
"""
|
|
|
f778fe |
if is_bundle(resource_el):
|
|
|
f778fe |
- # bundles currently cannot be disabled - pcmk does not support that
|
|
|
f778fe |
- # inner resources are supposed to be managed separately
|
|
|
f778fe |
- return []
|
|
|
f778fe |
+ to_enable = [resource_el]
|
|
|
f778fe |
+ in_bundle = get_bundle_inner_resource(resource_el)
|
|
|
f778fe |
+ if in_bundle is not None:
|
|
|
f778fe |
+ to_enable.append(in_bundle)
|
|
|
f778fe |
+ return to_enable
|
|
|
f778fe |
|
|
|
f778fe |
if is_any_clone(resource_el):
|
|
|
f778fe |
return [resource_el, get_clone_inner_resource(resource_el)]
|
|
|
f778fe |
|
|
|
f778fe |
to_enable = [resource_el]
|
|
|
f778fe |
parent = resource_el.getparent()
|
|
|
f778fe |
- if is_any_clone(parent):
|
|
|
f778fe |
+ if is_any_clone(parent) or is_bundle(parent):
|
|
|
f778fe |
to_enable.append(parent)
|
|
|
f778fe |
return to_enable
|
|
|
f778fe |
|
|
|
f778fe |
@@ -109,20 +111,25 @@ def find_resources_to_manage(resource_el):
|
|
|
f778fe |
# put there manually. If we didn't do it, the resource may stay unmanaged,
|
|
|
f778fe |
# as a managed primitive in an unmanaged clone / group is still unmanaged
|
|
|
f778fe |
# and vice versa.
|
|
|
f778fe |
- # Bundle resources cannot be set as unmanaged - pcmk currently doesn't
|
|
|
f778fe |
- # support that. Resources in a bundle are supposed to be treated separately.
|
|
|
f778fe |
- if is_bundle(resource_el):
|
|
|
f778fe |
- return []
|
|
|
f778fe |
res_id = resource_el.attrib["id"]
|
|
|
f778fe |
return (
|
|
|
f778fe |
[resource_el] # the resource itself
|
|
|
f778fe |
+
|
|
|
f778fe |
# its parents
|
|
|
f778fe |
find_parent(resource_el, "resources").xpath(
|
|
|
f778fe |
+ # a master or a clone which contains a group, a primitve, or a
|
|
|
f778fe |
+ # grouped primitive with the specified id
|
|
|
f778fe |
+ # OR
|
|
|
f778fe |
+ # a group (in a clone, master, etc. - hence //) which contains a
|
|
|
f778fe |
+ # primitive with the specified id
|
|
|
f778fe |
+ # OR
|
|
|
f778fe |
+ # a bundle which contains a primitive with the specified id
|
|
|
f778fe |
"""
|
|
|
f778fe |
(./master|./clone)[(group|group/primitive|primitive)[@id='{r}']]
|
|
|
f778fe |
|
|
|
|
f778fe |
//group[primitive[@id='{r}']]
|
|
|
f778fe |
+ |
|
|
|
f778fe |
+ ./bundle[primitive[@id='{r}']]
|
|
|
f778fe |
"""
|
|
|
f778fe |
.format(r=res_id)
|
|
|
f778fe |
)
|
|
|
f778fe |
@@ -164,10 +171,19 @@ def find_resources_to_unmanage(resource_el):
|
|
|
f778fe |
# See clone notes above
|
|
|
f778fe |
#
|
|
|
f778fe |
# a bundled primitive - the primitive - the primitive
|
|
|
f778fe |
- # a bundled primitive - the bundle - nothing
|
|
|
f778fe |
- # bundles currently cannot be set as unmanaged - pcmk does not support that
|
|
|
f778fe |
- # an empty bundle - the bundle - nothing
|
|
|
f778fe |
- # bundles currently cannot be set as unmanaged - pcmk does not support that
|
|
|
f778fe |
+ # a bundled primitive - the bundle - the bundle and the primitive
|
|
|
f778fe |
+ # We need to unmanage implicit resources create by pacemaker and there is
|
|
|
f778fe |
+ # no other way to do it than unmanage the bundle itself.
|
|
|
f778fe |
+ # Since it is not possible to unbundle a resource, the concers described
|
|
|
f778fe |
+ # at unclone don't apply here. However to prevent future bugs, in case
|
|
|
f778fe |
+ # unbundling becomes possible, we unmanage the primitive as well.
|
|
|
f778fe |
+ # an empty bundle - the bundle - the bundle
|
|
|
f778fe |
+ # There is nothing else to unmanage.
|
|
|
f778fe |
+ if is_bundle(resource_el):
|
|
|
f778fe |
+ in_bundle = get_bundle_inner_resource(resource_el)
|
|
|
f778fe |
+ return (
|
|
|
f778fe |
+ [resource_el, in_bundle] if in_bundle is not None else [resource_el]
|
|
|
f778fe |
+ )
|
|
|
f778fe |
if is_any_clone(resource_el):
|
|
|
f778fe |
resource_el = get_clone_inner_resource(resource_el)
|
|
|
f778fe |
if is_group(resource_el):
|
|
|
f778fe |
diff --git a/pcs/lib/cib/test/test_nvpair.py b/pcs/lib/cib/test/test_nvpair.py
|
|
|
f778fe |
index 9b9d9b9..0f6d8f8 100644
|
|
|
f778fe |
--- a/pcs/lib/cib/test/test_nvpair.py
|
|
|
f778fe |
+++ b/pcs/lib/cib/test/test_nvpair.py
|
|
|
f778fe |
@@ -8,6 +8,7 @@ from __future__ import (
|
|
|
f778fe |
from lxml import etree
|
|
|
f778fe |
|
|
|
f778fe |
from pcs.lib.cib import nvpair
|
|
|
f778fe |
+from pcs.lib.cib.tools import IdProvider
|
|
|
f778fe |
from pcs.test.tools.assertions import assert_xml_equal
|
|
|
f778fe |
from pcs.test.tools.pcs_unittest import TestCase, mock
|
|
|
f778fe |
from pcs.test.tools.xml import etree_to_str
|
|
|
f778fe |
@@ -25,6 +26,21 @@ class AppendNewNvpair(TestCase):
|
|
|
f778fe |
"""
|
|
|
f778fe |
)
|
|
|
f778fe |
|
|
|
f778fe |
+ def test_with_id_provider(self):
|
|
|
f778fe |
+ nvset_element = etree.fromstring('<nvset id="a"/>')
|
|
|
f778fe |
+ provider = IdProvider(nvset_element)
|
|
|
f778fe |
+ provider.book_ids("a-b")
|
|
|
f778fe |
+ nvpair._append_new_nvpair(nvset_element, "b", "c", provider)
|
|
|
f778fe |
+ assert_xml_equal(
|
|
|
f778fe |
+ etree_to_str(nvset_element),
|
|
|
f778fe |
+ """
|
|
|
f778fe |
+ <nvset id="a">
|
|
|
f778fe |
+ <nvpair id="a-b-1" name="b" value="c"></nvpair>
|
|
|
f778fe |
+ </nvset>
|
|
|
f778fe |
+ """
|
|
|
f778fe |
+ )
|
|
|
f778fe |
+
|
|
|
f778fe |
+
|
|
|
f778fe |
class UpdateNvsetTest(TestCase):
|
|
|
f778fe |
@mock.patch(
|
|
|
f778fe |
"pcs.lib.cib.nvpair.create_subelement_id",
|
|
|
f778fe |
@@ -167,6 +183,32 @@ class AppendNewNvsetTest(TestCase):
|
|
|
f778fe |
etree_to_str(context_element)
|
|
|
f778fe |
)
|
|
|
f778fe |
|
|
|
f778fe |
+ def test_with_id_provider(self):
|
|
|
f778fe |
+ context_element = etree.fromstring('<context id="a"/>')
|
|
|
f778fe |
+ provider = IdProvider(context_element)
|
|
|
f778fe |
+ provider.book_ids("a-instance_attributes", "a-instance_attributes-1-a")
|
|
|
f778fe |
+ nvpair.append_new_nvset(
|
|
|
f778fe |
+ "instance_attributes",
|
|
|
f778fe |
+ context_element,
|
|
|
f778fe |
+ {
|
|
|
f778fe |
+ "a": "b",
|
|
|
f778fe |
+ "c": "d",
|
|
|
f778fe |
+ },
|
|
|
f778fe |
+ provider
|
|
|
f778fe |
+ )
|
|
|
f778fe |
+ assert_xml_equal(
|
|
|
f778fe |
+ """
|
|
|
f778fe |
+ <context id="a">
|
|
|
f778fe |
+ <instance_attributes id="a-instance_attributes-1">
|
|
|
f778fe |
+ <nvpair id="a-instance_attributes-1-a-1" name="a" value="b"/>
|
|
|
f778fe |
+ <nvpair id="a-instance_attributes-1-c" name="c" value="d"/>
|
|
|
f778fe |
+ </instance_attributes>
|
|
|
f778fe |
+ </context>
|
|
|
f778fe |
+ """,
|
|
|
f778fe |
+ etree_to_str(context_element)
|
|
|
f778fe |
+ )
|
|
|
f778fe |
+
|
|
|
f778fe |
+
|
|
|
f778fe |
class ArrangeFirstNvsetTest(TestCase):
|
|
|
f778fe |
def setUp(self):
|
|
|
f778fe |
self.root = etree.Element("root", id="root")
|
|
|
f778fe |
diff --git a/pcs/lib/cib/test/test_resource_common.py b/pcs/lib/cib/test/test_resource_common.py
|
|
|
f778fe |
index 52c2329..6b485f7 100644
|
|
|
f778fe |
--- a/pcs/lib/cib/test/test_resource_common.py
|
|
|
f778fe |
+++ b/pcs/lib/cib/test/test_resource_common.py
|
|
|
f778fe |
@@ -180,7 +180,7 @@ class FindResourcesToEnable(TestCase):
|
|
|
f778fe |
self.assert_find_resources("F2", ["F2"])
|
|
|
f778fe |
|
|
|
f778fe |
def test_primitive_in_bundle(self):
|
|
|
f778fe |
- self.assert_find_resources("H", ["H"])
|
|
|
f778fe |
+ self.assert_find_resources("H", ["H", "H-bundle"])
|
|
|
f778fe |
|
|
|
f778fe |
def test_group(self):
|
|
|
f778fe |
self.assert_find_resources("D", ["D"])
|
|
|
f778fe |
@@ -204,10 +204,10 @@ class FindResourcesToEnable(TestCase):
|
|
|
f778fe |
self.assert_find_resources("F-master", ["F-master", "F"])
|
|
|
f778fe |
|
|
|
f778fe |
def test_bundle_empty(self):
|
|
|
f778fe |
- self.assert_find_resources("G-bundle", [])
|
|
|
f778fe |
+ self.assert_find_resources("G-bundle", ["G-bundle"])
|
|
|
f778fe |
|
|
|
f778fe |
def test_bundle_with_primitive(self):
|
|
|
f778fe |
- self.assert_find_resources("H-bundle", [])
|
|
|
f778fe |
+ self.assert_find_resources("H-bundle", ["H-bundle", "H"])
|
|
|
f778fe |
|
|
|
f778fe |
|
|
|
f778fe |
class Enable(TestCase):
|
|
|
f778fe |
@@ -360,7 +360,7 @@ class FindResourcesToManage(TestCase):
|
|
|
f778fe |
self.assert_find_resources("F2", ["F2", "F-master", "F"])
|
|
|
f778fe |
|
|
|
f778fe |
def test_primitive_in_bundle(self):
|
|
|
f778fe |
- self.assert_find_resources("H", ["H"])
|
|
|
f778fe |
+ self.assert_find_resources("H", ["H", "H-bundle"])
|
|
|
f778fe |
|
|
|
f778fe |
def test_group(self):
|
|
|
f778fe |
self.assert_find_resources("D", ["D", "D1", "D2"])
|
|
|
f778fe |
@@ -384,10 +384,10 @@ class FindResourcesToManage(TestCase):
|
|
|
f778fe |
self.assert_find_resources("F-master", ["F-master", "F", "F1", "F2"])
|
|
|
f778fe |
|
|
|
f778fe |
def test_bundle_empty(self):
|
|
|
f778fe |
- self.assert_find_resources("G-bundle", [])
|
|
|
f778fe |
+ self.assert_find_resources("G-bundle", ["G-bundle"])
|
|
|
f778fe |
|
|
|
f778fe |
def test_bundle_with_primitive(self):
|
|
|
f778fe |
- self.assert_find_resources("H-bundle", [])
|
|
|
f778fe |
+ self.assert_find_resources("H-bundle", ["H-bundle", "H"])
|
|
|
f778fe |
|
|
|
f778fe |
|
|
|
f778fe |
class FindResourcesToUnmanage(TestCase):
|
|
|
f778fe |
@@ -447,10 +447,10 @@ class FindResourcesToUnmanage(TestCase):
|
|
|
f778fe |
self.assert_find_resources("F-master", ["F1", "F2"])
|
|
|
f778fe |
|
|
|
f778fe |
def test_bundle_empty(self):
|
|
|
f778fe |
- self.assert_find_resources("G-bundle", [])
|
|
|
f778fe |
+ self.assert_find_resources("G-bundle", ["G-bundle"])
|
|
|
f778fe |
|
|
|
f778fe |
def test_bundle_with_primitive(self):
|
|
|
f778fe |
- self.assert_find_resources("H-bundle", [])
|
|
|
f778fe |
+ self.assert_find_resources("H-bundle", ["H-bundle", "H"])
|
|
|
f778fe |
|
|
|
f778fe |
|
|
|
f778fe |
class Manage(TestCase):
|
|
|
f778fe |
diff --git a/pcs/lib/cib/tools.py b/pcs/lib/cib/tools.py
|
|
|
f778fe |
index 2308a42..cf91125 100644
|
|
|
f778fe |
--- a/pcs/lib/cib/tools.py
|
|
|
f778fe |
+++ b/pcs/lib/cib/tools.py
|
|
|
f778fe |
@@ -177,11 +177,11 @@ def find_element_by_tag_and_id(
|
|
|
f778fe |
)
|
|
|
f778fe |
)
|
|
|
f778fe |
|
|
|
f778fe |
-def create_subelement_id(context_element, suffix):
|
|
|
f778fe |
- return find_unique_id(
|
|
|
f778fe |
- context_element,
|
|
|
f778fe |
- "{0}-{1}".format(context_element.get("id"), suffix)
|
|
|
f778fe |
- )
|
|
|
f778fe |
+def create_subelement_id(context_element, suffix, id_provider=None):
|
|
|
f778fe |
+ proposed_id = "{0}-{1}".format(context_element.get("id"), suffix)
|
|
|
f778fe |
+ if id_provider:
|
|
|
f778fe |
+ return id_provider.allocate_id(proposed_id)
|
|
|
f778fe |
+ return find_unique_id(context_element, proposed_id)
|
|
|
f778fe |
|
|
|
f778fe |
def check_new_id_applicable(tree, description, id):
|
|
|
f778fe |
validate_id(id, description)
|
|
|
f778fe |
diff --git a/pcs/lib/commands/resource.py b/pcs/lib/commands/resource.py
|
|
|
f778fe |
index 3a060b8..0c5f682 100644
|
|
|
f778fe |
--- a/pcs/lib/commands/resource.py
|
|
|
f778fe |
+++ b/pcs/lib/commands/resource.py
|
|
|
f778fe |
@@ -22,6 +22,7 @@ from pcs.lib.errors import LibraryError
|
|
|
f778fe |
from pcs.lib.pacemaker.values import validate_id
|
|
|
f778fe |
from pcs.lib.pacemaker.state import (
|
|
|
f778fe |
ensure_resource_state,
|
|
|
f778fe |
+ info_resource_state,
|
|
|
f778fe |
is_resource_managed,
|
|
|
f778fe |
ResourceNotFound,
|
|
|
f778fe |
)
|
|
|
f778fe |
@@ -31,7 +32,10 @@ from pcs.lib.resource_agent import(
|
|
|
f778fe |
|
|
|
f778fe |
@contextmanager
|
|
|
f778fe |
def resource_environment(
|
|
|
f778fe |
- env, wait=False, wait_for_resource_ids=None, disabled_after_wait=False,
|
|
|
f778fe |
+ env,
|
|
|
f778fe |
+ wait=False,
|
|
|
f778fe |
+ wait_for_resource_ids=None,
|
|
|
f778fe |
+ resource_state_reporter=info_resource_state,
|
|
|
f778fe |
required_cib_version=None
|
|
|
f778fe |
):
|
|
|
f778fe |
env.ensure_wait_satisfiable(wait)
|
|
|
f778fe |
@@ -41,10 +45,19 @@ def resource_environment(
|
|
|
f778fe |
if wait is not False and wait_for_resource_ids:
|
|
|
f778fe |
state = env.get_cluster_state()
|
|
|
f778fe |
env.report_processor.process_list([
|
|
|
f778fe |
- ensure_resource_state(not disabled_after_wait, state, res_id)
|
|
|
f778fe |
+ resource_state_reporter(state, res_id)
|
|
|
f778fe |
for res_id in wait_for_resource_ids
|
|
|
f778fe |
])
|
|
|
f778fe |
|
|
|
f778fe |
+def _ensure_disabled_after_wait(disabled_after_wait):
|
|
|
f778fe |
+ def inner(state, resource_id):
|
|
|
f778fe |
+ return ensure_resource_state(
|
|
|
f778fe |
+ not disabled_after_wait,
|
|
|
f778fe |
+ state,
|
|
|
f778fe |
+ resource_id
|
|
|
f778fe |
+ )
|
|
|
f778fe |
+ return inner
|
|
|
f778fe |
+
|
|
|
f778fe |
def _validate_remote_connection(
|
|
|
f778fe |
resource_agent, nodes_to_validate_against, resource_id, instance_attributes,
|
|
|
f778fe |
allow_not_suitable_command
|
|
|
f778fe |
@@ -195,7 +208,11 @@ def create(
|
|
|
f778fe |
env,
|
|
|
f778fe |
wait,
|
|
|
f778fe |
[resource_id],
|
|
|
f778fe |
- ensure_disabled or resource.common.are_meta_disabled(meta_attributes),
|
|
|
f778fe |
+ _ensure_disabled_after_wait(
|
|
|
f778fe |
+ ensure_disabled
|
|
|
f778fe |
+ or
|
|
|
f778fe |
+ resource.common.are_meta_disabled(meta_attributes)
|
|
|
f778fe |
+ )
|
|
|
f778fe |
) as resources_section:
|
|
|
f778fe |
_check_special_cases(
|
|
|
f778fe |
env,
|
|
|
f778fe |
@@ -269,7 +286,7 @@ def _create_as_clone_common(
|
|
|
f778fe |
env,
|
|
|
f778fe |
wait,
|
|
|
f778fe |
[resource_id],
|
|
|
f778fe |
- (
|
|
|
f778fe |
+ _ensure_disabled_after_wait(
|
|
|
f778fe |
ensure_disabled
|
|
|
f778fe |
or
|
|
|
f778fe |
resource.common.are_meta_disabled(meta_attributes)
|
|
|
f778fe |
@@ -353,7 +370,11 @@ def create_in_group(
|
|
|
f778fe |
env,
|
|
|
f778fe |
wait,
|
|
|
f778fe |
[resource_id],
|
|
|
f778fe |
- ensure_disabled or resource.common.are_meta_disabled(meta_attributes),
|
|
|
f778fe |
+ _ensure_disabled_after_wait(
|
|
|
f778fe |
+ ensure_disabled
|
|
|
f778fe |
+ or
|
|
|
f778fe |
+ resource.common.are_meta_disabled(meta_attributes)
|
|
|
f778fe |
+ )
|
|
|
f778fe |
) as resources_section:
|
|
|
f778fe |
_check_special_cases(
|
|
|
f778fe |
env,
|
|
|
f778fe |
@@ -433,7 +454,11 @@ def create_into_bundle(
|
|
|
f778fe |
env,
|
|
|
f778fe |
wait,
|
|
|
f778fe |
[resource_id],
|
|
|
f778fe |
- disabled_after_wait=ensure_disabled,
|
|
|
f778fe |
+ _ensure_disabled_after_wait(
|
|
|
f778fe |
+ ensure_disabled
|
|
|
f778fe |
+ or
|
|
|
f778fe |
+ resource.common.are_meta_disabled(meta_attributes)
|
|
|
f778fe |
+ ),
|
|
|
f778fe |
required_cib_version=(2, 8, 0)
|
|
|
f778fe |
) as resources_section:
|
|
|
f778fe |
_check_special_cases(
|
|
|
f778fe |
@@ -465,8 +490,9 @@ def create_into_bundle(
|
|
|
f778fe |
|
|
|
f778fe |
def bundle_create(
|
|
|
f778fe |
env, bundle_id, container_type, container_options=None,
|
|
|
f778fe |
- network_options=None, port_map=None, storage_map=None,
|
|
|
f778fe |
+ network_options=None, port_map=None, storage_map=None, meta_attributes=None,
|
|
|
f778fe |
force_options=False,
|
|
|
f778fe |
+ ensure_disabled=False,
|
|
|
f778fe |
wait=False,
|
|
|
f778fe |
):
|
|
|
f778fe |
"""
|
|
|
f778fe |
@@ -477,24 +503,32 @@ def bundle_create(
|
|
|
f778fe |
string container_type -- container engine name (docker, lxc...)
|
|
|
f778fe |
dict container_options -- container options
|
|
|
f778fe |
dict network_options -- network options
|
|
|
f778fe |
- list of dict port_map -- list of port mapping options
|
|
|
f778fe |
- list of dict storage_map -- list of storage mapping options
|
|
|
f778fe |
+ list of dict port_map -- a list of port mapping options
|
|
|
f778fe |
+ list of dict storage_map -- a list of storage mapping options
|
|
|
f778fe |
+ dict meta_attributes -- bundle's meta attributes
|
|
|
f778fe |
bool force_options -- return warnings instead of forceable errors
|
|
|
f778fe |
+ bool ensure_disabled -- set the bundle's target-role to "Stopped"
|
|
|
f778fe |
mixed wait -- False: no wait, None: wait default timeout, int: wait timeout
|
|
|
f778fe |
"""
|
|
|
f778fe |
container_options = container_options or {}
|
|
|
f778fe |
network_options = network_options or {}
|
|
|
f778fe |
port_map = port_map or []
|
|
|
f778fe |
storage_map = storage_map or []
|
|
|
f778fe |
+ meta_attributes = meta_attributes or {}
|
|
|
f778fe |
|
|
|
f778fe |
with resource_environment(
|
|
|
f778fe |
env,
|
|
|
f778fe |
wait,
|
|
|
f778fe |
[bundle_id],
|
|
|
f778fe |
- # bundles are always enabled, currently there is no way to disable them
|
|
|
f778fe |
- disabled_after_wait=False,
|
|
|
f778fe |
+ _ensure_disabled_after_wait(
|
|
|
f778fe |
+ ensure_disabled
|
|
|
f778fe |
+ or
|
|
|
f778fe |
+ resource.common.are_meta_disabled(meta_attributes)
|
|
|
f778fe |
+ ),
|
|
|
f778fe |
required_cib_version=(2, 8, 0)
|
|
|
f778fe |
) as resources_section:
|
|
|
f778fe |
+ # no need to run validations related to remote and guest nodes as those
|
|
|
f778fe |
+ # nodes can only be created from primitive resources
|
|
|
f778fe |
id_provider = IdProvider(resources_section)
|
|
|
f778fe |
env.report_processor.process_list(
|
|
|
f778fe |
resource.bundle.validate_new(
|
|
|
f778fe |
@@ -505,10 +539,11 @@ def bundle_create(
|
|
|
f778fe |
network_options,
|
|
|
f778fe |
port_map,
|
|
|
f778fe |
storage_map,
|
|
|
f778fe |
+ # TODO meta attributes - there is no validation for now
|
|
|
f778fe |
force_options
|
|
|
f778fe |
)
|
|
|
f778fe |
)
|
|
|
f778fe |
- resource.bundle.append_new(
|
|
|
f778fe |
+ bundle_element = resource.bundle.append_new(
|
|
|
f778fe |
resources_section,
|
|
|
f778fe |
id_provider,
|
|
|
f778fe |
bundle_id,
|
|
|
f778fe |
@@ -516,13 +551,16 @@ def bundle_create(
|
|
|
f778fe |
container_options,
|
|
|
f778fe |
network_options,
|
|
|
f778fe |
port_map,
|
|
|
f778fe |
- storage_map
|
|
|
f778fe |
+ storage_map,
|
|
|
f778fe |
+ meta_attributes
|
|
|
f778fe |
)
|
|
|
f778fe |
+ if ensure_disabled:
|
|
|
f778fe |
+ resource.common.disable(bundle_element)
|
|
|
f778fe |
|
|
|
f778fe |
def bundle_update(
|
|
|
f778fe |
env, bundle_id, container_options=None, network_options=None,
|
|
|
f778fe |
port_map_add=None, port_map_remove=None, storage_map_add=None,
|
|
|
f778fe |
- storage_map_remove=None,
|
|
|
f778fe |
+ storage_map_remove=None, meta_attributes=None,
|
|
|
f778fe |
force_options=False,
|
|
|
f778fe |
wait=False,
|
|
|
f778fe |
):
|
|
|
f778fe |
@@ -537,6 +575,7 @@ def bundle_update(
|
|
|
f778fe |
list of string port_map_remove -- list of port mapping ids to remove
|
|
|
f778fe |
list of dict storage_map_add -- list of storage mapping options to add
|
|
|
f778fe |
list of string storage_map_remove -- list of storage mapping ids to remove
|
|
|
f778fe |
+ dict meta_attributes -- meta attributes to update
|
|
|
f778fe |
bool force_options -- return warnings instead of forceable errors
|
|
|
f778fe |
mixed wait -- False: no wait, None: wait default timeout, int: wait timeout
|
|
|
f778fe |
"""
|
|
|
f778fe |
@@ -546,15 +585,16 @@ def bundle_update(
|
|
|
f778fe |
port_map_remove = port_map_remove or []
|
|
|
f778fe |
storage_map_add = storage_map_add or []
|
|
|
f778fe |
storage_map_remove = storage_map_remove or []
|
|
|
f778fe |
+ meta_attributes = meta_attributes or {}
|
|
|
f778fe |
|
|
|
f778fe |
with resource_environment(
|
|
|
f778fe |
env,
|
|
|
f778fe |
wait,
|
|
|
f778fe |
[bundle_id],
|
|
|
f778fe |
- # bundles are always enabled, currently there is no way to disable them
|
|
|
f778fe |
- disabled_after_wait=False,
|
|
|
f778fe |
required_cib_version=(2, 8, 0)
|
|
|
f778fe |
) as resources_section:
|
|
|
f778fe |
+ # no need to run validations related to remote and guest nodes as those
|
|
|
f778fe |
+ # nodes can only be created from primitive resources
|
|
|
f778fe |
id_provider = IdProvider(resources_section)
|
|
|
f778fe |
bundle_element = find_element_by_tag_and_id(
|
|
|
f778fe |
resource.bundle.TAG,
|
|
|
f778fe |
@@ -571,6 +611,7 @@ def bundle_update(
|
|
|
f778fe |
port_map_remove,
|
|
|
f778fe |
storage_map_add,
|
|
|
f778fe |
storage_map_remove,
|
|
|
f778fe |
+ # TODO meta attributes - there is no validation for now
|
|
|
f778fe |
force_options
|
|
|
f778fe |
)
|
|
|
f778fe |
)
|
|
|
f778fe |
@@ -582,7 +623,8 @@ def bundle_update(
|
|
|
f778fe |
port_map_add,
|
|
|
f778fe |
port_map_remove,
|
|
|
f778fe |
storage_map_add,
|
|
|
f778fe |
- storage_map_remove
|
|
|
f778fe |
+ storage_map_remove,
|
|
|
f778fe |
+ meta_attributes
|
|
|
f778fe |
)
|
|
|
f778fe |
|
|
|
f778fe |
def disable(env, resource_ids, wait):
|
|
|
f778fe |
@@ -593,7 +635,7 @@ def disable(env, resource_ids, wait):
|
|
|
f778fe |
mixed wait -- False: no wait, None: wait default timeout, int: wait timeout
|
|
|
f778fe |
"""
|
|
|
f778fe |
with resource_environment(
|
|
|
f778fe |
- env, wait, resource_ids, True
|
|
|
f778fe |
+ env, wait, resource_ids, _ensure_disabled_after_wait(True)
|
|
|
f778fe |
) as resources_section:
|
|
|
f778fe |
resource_el_list = _find_resources_or_raise(
|
|
|
f778fe |
resources_section,
|
|
|
f778fe |
@@ -615,7 +657,7 @@ def enable(env, resource_ids, wait):
|
|
|
f778fe |
mixed wait -- False: no wait, None: wait default timeout, int: wait timeout
|
|
|
f778fe |
"""
|
|
|
f778fe |
with resource_environment(
|
|
|
f778fe |
- env, wait, resource_ids, False
|
|
|
f778fe |
+ env, wait, resource_ids, _ensure_disabled_after_wait(False)
|
|
|
f778fe |
) as resources_section:
|
|
|
f778fe |
resource_el_list = _find_resources_or_raise(
|
|
|
f778fe |
resources_section,
|
|
|
f778fe |
@@ -642,7 +684,7 @@ def _resource_list_enable_disable(resource_el_list, func, cluster_state):
|
|
|
f778fe |
report_list.append(
|
|
|
f778fe |
reports.id_not_found(
|
|
|
f778fe |
res_id,
|
|
|
f778fe |
- id_description="resource/clone/master/group"
|
|
|
f778fe |
+ id_description="resource/clone/master/group/bundle"
|
|
|
f778fe |
)
|
|
|
f778fe |
)
|
|
|
f778fe |
return report_list
|
|
|
f778fe |
@@ -735,7 +777,7 @@ def _find_resources_or_raise(
|
|
|
f778fe |
resource_tags = (
|
|
|
f778fe |
resource.clone.ALL_TAGS
|
|
|
f778fe |
+
|
|
|
f778fe |
- [resource.group.TAG, resource.primitive.TAG]
|
|
|
f778fe |
+ [resource.group.TAG, resource.primitive.TAG, resource.bundle.TAG]
|
|
|
f778fe |
)
|
|
|
f778fe |
for res_id in resource_ids:
|
|
|
f778fe |
try:
|
|
|
f778fe |
@@ -745,7 +787,7 @@ def _find_resources_or_raise(
|
|
|
f778fe |
resource_tags,
|
|
|
f778fe |
resources_section,
|
|
|
f778fe |
res_id,
|
|
|
f778fe |
- id_description="resource/clone/master/group"
|
|
|
f778fe |
+ id_description="resource/clone/master/group/bundle"
|
|
|
f778fe |
)
|
|
|
f778fe |
)
|
|
|
f778fe |
)
|
|
|
f778fe |
diff --git a/pcs/lib/commands/test/resource/fixture.py b/pcs/lib/commands/test/resource/fixture.py
|
|
|
f778fe |
index f1fe09b..8d96dc9 100644
|
|
|
f778fe |
--- a/pcs/lib/commands/test/resource/fixture.py
|
|
|
f778fe |
+++ b/pcs/lib/commands/test/resource/fixture.py
|
|
|
f778fe |
@@ -145,7 +145,7 @@ def report_not_found(res_id, context_type=""):
|
|
|
f778fe |
"context_type": context_type,
|
|
|
f778fe |
"context_id": "",
|
|
|
f778fe |
"id": res_id,
|
|
|
f778fe |
- "id_description": "resource/clone/master/group",
|
|
|
f778fe |
+ "id_description": "resource/clone/master/group/bundle",
|
|
|
f778fe |
},
|
|
|
f778fe |
None
|
|
|
f778fe |
)
|
|
|
f778fe |
diff --git a/pcs/lib/commands/test/resource/test_bundle_create.py b/pcs/lib/commands/test/resource/test_bundle_create.py
|
|
|
f778fe |
index b9922d8..3bdeee9 100644
|
|
|
f778fe |
--- a/pcs/lib/commands/test/resource/test_bundle_create.py
|
|
|
f778fe |
+++ b/pcs/lib/commands/test/resource/test_bundle_create.py
|
|
|
f778fe |
@@ -40,7 +40,7 @@ class MinimalCreate(CommonTest):
|
|
|
f778fe |
self.fixture_cib_pre,
|
|
|
f778fe |
lambda: resource.bundle_create(
|
|
|
f778fe |
self.env, "B1", "docker",
|
|
|
f778fe |
- {"image": "pcs:test", }
|
|
|
f778fe |
+ container_options={"image": "pcs:test", }
|
|
|
f778fe |
),
|
|
|
f778fe |
self.fixture_resources_bundle_simple
|
|
|
f778fe |
)
|
|
|
f778fe |
@@ -90,7 +90,7 @@ class MinimalCreate(CommonTest):
|
|
|
f778fe |
|
|
|
f778fe |
resource.bundle_create(
|
|
|
f778fe |
self.env, "B1", "docker",
|
|
|
f778fe |
- {"image": "pcs:test", }
|
|
|
f778fe |
+ container_options={"image": "pcs:test", }
|
|
|
f778fe |
)
|
|
|
f778fe |
|
|
|
f778fe |
self.env.report_processor.assert_reports([
|
|
|
f778fe |
@@ -122,7 +122,7 @@ class CreateDocker(CommonTest):
|
|
|
f778fe |
self.fixture_cib_pre,
|
|
|
f778fe |
lambda: resource.bundle_create(
|
|
|
f778fe |
self.env, "B1", "docker",
|
|
|
f778fe |
- {"image": "pcs:test", }
|
|
|
f778fe |
+ container_options={"image": "pcs:test", }
|
|
|
f778fe |
),
|
|
|
f778fe |
self.fixture_resources_bundle_simple
|
|
|
f778fe |
)
|
|
|
f778fe |
@@ -132,7 +132,7 @@ class CreateDocker(CommonTest):
|
|
|
f778fe |
self.fixture_cib_pre,
|
|
|
f778fe |
lambda: resource.bundle_create(
|
|
|
f778fe |
self.env, "B1", "docker",
|
|
|
f778fe |
- {
|
|
|
f778fe |
+ container_options={
|
|
|
f778fe |
"image": "pcs:test",
|
|
|
f778fe |
"masters": "0",
|
|
|
f778fe |
"network": "extra network settings",
|
|
|
f778fe |
@@ -168,7 +168,7 @@ class CreateDocker(CommonTest):
|
|
|
f778fe |
assert_raise_library_error(
|
|
|
f778fe |
lambda: resource.bundle_create(
|
|
|
f778fe |
self.env, "B1", "docker",
|
|
|
f778fe |
- {
|
|
|
f778fe |
+ container_options={
|
|
|
f778fe |
"replicas-per-host": "0",
|
|
|
f778fe |
"replicas": "0",
|
|
|
f778fe |
"masters": "-1",
|
|
|
f778fe |
@@ -226,7 +226,7 @@ class CreateDocker(CommonTest):
|
|
|
f778fe |
assert_raise_library_error(
|
|
|
f778fe |
lambda: resource.bundle_create(
|
|
|
f778fe |
self.env, "B1", "docker",
|
|
|
f778fe |
- {
|
|
|
f778fe |
+ container_options={
|
|
|
f778fe |
"image": "",
|
|
|
f778fe |
},
|
|
|
f778fe |
force_options=True
|
|
|
f778fe |
@@ -253,7 +253,7 @@ class CreateDocker(CommonTest):
|
|
|
f778fe |
assert_raise_library_error(
|
|
|
f778fe |
lambda: resource.bundle_create(
|
|
|
f778fe |
self.env, "B1", "docker",
|
|
|
f778fe |
- {
|
|
|
f778fe |
+ container_options={
|
|
|
f778fe |
"image": "pcs:test",
|
|
|
f778fe |
"extra": "option",
|
|
|
f778fe |
}
|
|
|
f778fe |
@@ -276,7 +276,7 @@ class CreateDocker(CommonTest):
|
|
|
f778fe |
self.fixture_cib_pre,
|
|
|
f778fe |
lambda: resource.bundle_create(
|
|
|
f778fe |
self.env, "B1", "docker",
|
|
|
f778fe |
- {
|
|
|
f778fe |
+ container_options={
|
|
|
f778fe |
"image": "pcs:test",
|
|
|
f778fe |
"extra": "option",
|
|
|
f778fe |
},
|
|
|
f778fe |
@@ -932,13 +932,61 @@ class CreateWithStorageMap(CommonTest):
|
|
|
f778fe |
)
|
|
|
f778fe |
|
|
|
f778fe |
|
|
|
f778fe |
+class CreateWithMeta(CommonTest):
|
|
|
f778fe |
+ def test_success(self):
|
|
|
f778fe |
+ self.assert_command_effect(
|
|
|
f778fe |
+ self.fixture_cib_pre,
|
|
|
f778fe |
+ lambda: resource.bundle_create(
|
|
|
f778fe |
+ self.env, "B1", "docker",
|
|
|
f778fe |
+ container_options={"image": "pcs:test", },
|
|
|
f778fe |
+ meta_attributes={
|
|
|
f778fe |
+ "target-role": "Stopped",
|
|
|
f778fe |
+ "is-managed": "false",
|
|
|
f778fe |
+ }
|
|
|
f778fe |
+ ),
|
|
|
f778fe |
+ """
|
|
|
f778fe |
+ <resources>
|
|
|
f778fe |
+ <bundle id="B1">
|
|
|
f778fe |
+ <docker image="pcs:test" />
|
|
|
f778fe |
+ <meta_attributes id="B1-meta_attributes">
|
|
|
f778fe |
+
|
|
|
f778fe |
+ name="is-managed" value="false" />
|
|
|
f778fe |
+
|
|
|
f778fe |
+ name="target-role" value="Stopped" />
|
|
|
f778fe |
+ </meta_attributes>
|
|
|
f778fe |
+ </bundle>
|
|
|
f778fe |
+ </resources>
|
|
|
f778fe |
+ """
|
|
|
f778fe |
+ )
|
|
|
f778fe |
+
|
|
|
f778fe |
+ def test_disabled(self):
|
|
|
f778fe |
+ self.assert_command_effect(
|
|
|
f778fe |
+ self.fixture_cib_pre,
|
|
|
f778fe |
+ lambda: resource.bundle_create(
|
|
|
f778fe |
+ self.env, "B1", "docker",
|
|
|
f778fe |
+ container_options={"image": "pcs:test", },
|
|
|
f778fe |
+ ensure_disabled=True
|
|
|
f778fe |
+ ),
|
|
|
f778fe |
+ """
|
|
|
f778fe |
+ <resources>
|
|
|
f778fe |
+ <bundle id="B1">
|
|
|
f778fe |
+ <meta_attributes id="B1-meta_attributes">
|
|
|
f778fe |
+
|
|
|
f778fe |
+ name="target-role" value="Stopped" />
|
|
|
f778fe |
+ </meta_attributes>
|
|
|
f778fe |
+ <docker image="pcs:test" />
|
|
|
f778fe |
+ </bundle>
|
|
|
f778fe |
+ </resources>
|
|
|
f778fe |
+ """
|
|
|
f778fe |
+ )
|
|
|
f778fe |
+
|
|
|
f778fe |
class CreateWithAllOptions(CommonTest):
|
|
|
f778fe |
def test_success(self):
|
|
|
f778fe |
self.assert_command_effect(
|
|
|
f778fe |
self.fixture_cib_pre,
|
|
|
f778fe |
lambda: resource.bundle_create(
|
|
|
f778fe |
self.env, "B1", "docker",
|
|
|
f778fe |
- {
|
|
|
f778fe |
+ container_options={
|
|
|
f778fe |
"image": "pcs:test",
|
|
|
f778fe |
"masters": "0",
|
|
|
f778fe |
"network": "extra network settings",
|
|
|
f778fe |
@@ -947,13 +995,13 @@ class CreateWithAllOptions(CommonTest):
|
|
|
f778fe |
"replicas": "4",
|
|
|
f778fe |
"replicas-per-host": "2",
|
|
|
f778fe |
},
|
|
|
f778fe |
- {
|
|
|
f778fe |
+ network_options={
|
|
|
f778fe |
"control-port": "12345",
|
|
|
f778fe |
"host-interface": "eth0",
|
|
|
f778fe |
"host-netmask": "24",
|
|
|
f778fe |
"ip-range-start": "192.168.100.200",
|
|
|
f778fe |
},
|
|
|
f778fe |
- [
|
|
|
f778fe |
+ port_map=[
|
|
|
f778fe |
{
|
|
|
f778fe |
"port": "1001",
|
|
|
f778fe |
},
|
|
|
f778fe |
@@ -967,7 +1015,7 @@ class CreateWithAllOptions(CommonTest):
|
|
|
f778fe |
"range": "3000-3300",
|
|
|
f778fe |
},
|
|
|
f778fe |
],
|
|
|
f778fe |
- [
|
|
|
f778fe |
+ storage_map=[
|
|
|
f778fe |
{
|
|
|
f778fe |
"source-dir": "/tmp/docker1a",
|
|
|
f778fe |
"target-dir": "/tmp/docker1b",
|
|
|
f778fe |
@@ -1082,21 +1130,26 @@ class Wait(CommonTest):
|
|
|
f778fe |
</resources>
|
|
|
f778fe |
"""
|
|
|
f778fe |
|
|
|
f778fe |
- timeout = 10
|
|
|
f778fe |
+ fixture_resources_bundle_simple_disabled = """
|
|
|
f778fe |
+ <resources>
|
|
|
f778fe |
+ <bundle id="B1">
|
|
|
f778fe |
+ <meta_attributes id="B1-meta_attributes">
|
|
|
f778fe |
+
|
|
|
f778fe |
+ name="target-role" value="Stopped" />
|
|
|
f778fe |
+ </meta_attributes>
|
|
|
f778fe |
+ <docker image="pcs:test" />
|
|
|
f778fe |
+ </bundle>
|
|
|
f778fe |
+ </resources>
|
|
|
f778fe |
+ """
|
|
|
f778fe |
|
|
|
f778fe |
- def fixture_calls_initial(self):
|
|
|
f778fe |
- return (
|
|
|
f778fe |
- fixture.call_wait_supported() +
|
|
|
f778fe |
- fixture.calls_cib(
|
|
|
f778fe |
- self.fixture_cib_pre,
|
|
|
f778fe |
- self.fixture_resources_bundle_simple,
|
|
|
f778fe |
- cib_base_file=self.cib_base_file,
|
|
|
f778fe |
- )
|
|
|
f778fe |
- )
|
|
|
f778fe |
+ timeout = 10
|
|
|
f778fe |
|
|
|
f778fe |
- def simple_bundle_create(self, wait=False):
|
|
|
f778fe |
+ def simple_bundle_create(self, wait=False, disabled=False):
|
|
|
f778fe |
return resource.bundle_create(
|
|
|
f778fe |
- self.env, "B1", "docker", {"image": "pcs:test"}, wait=wait,
|
|
|
f778fe |
+ self.env, "B1", "docker",
|
|
|
f778fe |
+ container_options={"image": "pcs:test"},
|
|
|
f778fe |
+ ensure_disabled=disabled,
|
|
|
f778fe |
+ wait=wait,
|
|
|
f778fe |
)
|
|
|
f778fe |
|
|
|
f778fe |
def test_wait_fail(self):
|
|
|
f778fe |
@@ -1108,7 +1161,14 @@ class Wait(CommonTest):
|
|
|
f778fe |
"""
|
|
|
f778fe |
)
|
|
|
f778fe |
self.runner.set_runs(
|
|
|
f778fe |
- self.fixture_calls_initial() +
|
|
|
f778fe |
+ fixture.call_wait_supported()
|
|
|
f778fe |
+ +
|
|
|
f778fe |
+ fixture.calls_cib(
|
|
|
f778fe |
+ self.fixture_cib_pre,
|
|
|
f778fe |
+ self.fixture_resources_bundle_simple,
|
|
|
f778fe |
+ cib_base_file=self.cib_base_file,
|
|
|
f778fe |
+ )
|
|
|
f778fe |
+ +
|
|
|
f778fe |
fixture.call_wait(self.timeout, 62, fixture_wait_timeout_error)
|
|
|
f778fe |
)
|
|
|
f778fe |
assert_raise_library_error(
|
|
|
f778fe |
@@ -1122,8 +1182,16 @@ class Wait(CommonTest):
|
|
|
f778fe |
@skip_unless_pacemaker_supports_bundle
|
|
|
f778fe |
def test_wait_ok_run_ok(self):
|
|
|
f778fe |
self.runner.set_runs(
|
|
|
f778fe |
- self.fixture_calls_initial() +
|
|
|
f778fe |
- fixture.call_wait(self.timeout) +
|
|
|
f778fe |
+ fixture.call_wait_supported()
|
|
|
f778fe |
+ +
|
|
|
f778fe |
+ fixture.calls_cib(
|
|
|
f778fe |
+ self.fixture_cib_pre,
|
|
|
f778fe |
+ self.fixture_resources_bundle_simple,
|
|
|
f778fe |
+ cib_base_file=self.cib_base_file,
|
|
|
f778fe |
+ )
|
|
|
f778fe |
+ +
|
|
|
f778fe |
+ fixture.call_wait(self.timeout)
|
|
|
f778fe |
+ +
|
|
|
f778fe |
fixture.call_status(fixture.state_complete(
|
|
|
f778fe |
self.fixture_status_running
|
|
|
f778fe |
))
|
|
|
f778fe |
@@ -1139,8 +1207,16 @@ class Wait(CommonTest):
|
|
|
f778fe |
@skip_unless_pacemaker_supports_bundle
|
|
|
f778fe |
def test_wait_ok_run_fail(self):
|
|
|
f778fe |
self.runner.set_runs(
|
|
|
f778fe |
- self.fixture_calls_initial() +
|
|
|
f778fe |
- fixture.call_wait(self.timeout) +
|
|
|
f778fe |
+ fixture.call_wait_supported()
|
|
|
f778fe |
+ +
|
|
|
f778fe |
+ fixture.calls_cib(
|
|
|
f778fe |
+ self.fixture_cib_pre,
|
|
|
f778fe |
+ self.fixture_resources_bundle_simple,
|
|
|
f778fe |
+ cib_base_file=self.cib_base_file,
|
|
|
f778fe |
+ )
|
|
|
f778fe |
+ +
|
|
|
f778fe |
+ fixture.call_wait(self.timeout)
|
|
|
f778fe |
+ +
|
|
|
f778fe |
fixture.call_status(fixture.state_complete(
|
|
|
f778fe |
self.fixture_status_not_running
|
|
|
f778fe |
))
|
|
|
f778fe |
@@ -1150,3 +1226,48 @@ class Wait(CommonTest):
|
|
|
f778fe |
fixture.report_resource_not_running("B1", severities.ERROR),
|
|
|
f778fe |
)
|
|
|
f778fe |
self.runner.assert_everything_launched()
|
|
|
f778fe |
+
|
|
|
f778fe |
+ @skip_unless_pacemaker_supports_bundle
|
|
|
f778fe |
+ def test_disabled_wait_ok_run_ok(self):
|
|
|
f778fe |
+ self.runner.set_runs(
|
|
|
f778fe |
+ fixture.call_wait_supported()
|
|
|
f778fe |
+ +
|
|
|
f778fe |
+ fixture.calls_cib(
|
|
|
f778fe |
+ self.fixture_cib_pre,
|
|
|
f778fe |
+ self.fixture_resources_bundle_simple_disabled,
|
|
|
f778fe |
+ cib_base_file=self.cib_base_file,
|
|
|
f778fe |
+ )
|
|
|
f778fe |
+ +
|
|
|
f778fe |
+ fixture.call_wait(self.timeout)
|
|
|
f778fe |
+ +
|
|
|
f778fe |
+ fixture.call_status(fixture.state_complete(
|
|
|
f778fe |
+ self.fixture_status_not_running
|
|
|
f778fe |
+ ))
|
|
|
f778fe |
+ )
|
|
|
f778fe |
+ self.simple_bundle_create(self.timeout, disabled=True)
|
|
|
f778fe |
+ self.runner.assert_everything_launched()
|
|
|
f778fe |
+
|
|
|
f778fe |
+ @skip_unless_pacemaker_supports_bundle
|
|
|
f778fe |
+ def test_disabled_wait_ok_run_fail(self):
|
|
|
f778fe |
+ self.runner.set_runs(
|
|
|
f778fe |
+ fixture.call_wait_supported()
|
|
|
f778fe |
+ +
|
|
|
f778fe |
+ fixture.calls_cib(
|
|
|
f778fe |
+ self.fixture_cib_pre,
|
|
|
f778fe |
+ self.fixture_resources_bundle_simple_disabled,
|
|
|
f778fe |
+ cib_base_file=self.cib_base_file,
|
|
|
f778fe |
+ )
|
|
|
f778fe |
+ +
|
|
|
f778fe |
+ fixture.call_wait(self.timeout)
|
|
|
f778fe |
+ +
|
|
|
f778fe |
+ fixture.call_status(fixture.state_complete(
|
|
|
f778fe |
+ self.fixture_status_running
|
|
|
f778fe |
+ ))
|
|
|
f778fe |
+ )
|
|
|
f778fe |
+ assert_raise_library_error(
|
|
|
f778fe |
+ lambda: self.simple_bundle_create(self.timeout, disabled=True),
|
|
|
f778fe |
+ fixture.report_resource_running(
|
|
|
f778fe |
+ "B1", {"Started": ["node1", "node2"]}, severities.ERROR
|
|
|
f778fe |
+ )
|
|
|
f778fe |
+ )
|
|
|
f778fe |
+ self.runner.assert_everything_launched()
|
|
|
f778fe |
diff --git a/pcs/lib/commands/test/resource/test_bundle_update.py b/pcs/lib/commands/test/resource/test_bundle_update.py
|
|
|
f778fe |
index 55cfa7b..7a1ee49 100644
|
|
|
f778fe |
--- a/pcs/lib/commands/test/resource/test_bundle_update.py
|
|
|
f778fe |
+++ b/pcs/lib/commands/test/resource/test_bundle_update.py
|
|
|
f778fe |
@@ -709,6 +709,96 @@ class StorageMap(CommonTest):
|
|
|
f778fe |
self.runner.assert_everything_launched()
|
|
|
f778fe |
|
|
|
f778fe |
|
|
|
f778fe |
+class Meta(CommonTest):
|
|
|
f778fe |
+ fixture_no_meta = """
|
|
|
f778fe |
+ <resources>
|
|
|
f778fe |
+ <bundle id="B1">
|
|
|
f778fe |
+ <docker image="pcs:test" masters="3" replicas="6"/>
|
|
|
f778fe |
+ </bundle>
|
|
|
f778fe |
+ </resources>
|
|
|
f778fe |
+ """
|
|
|
f778fe |
+
|
|
|
f778fe |
+ fixture_meta_stopped = """
|
|
|
f778fe |
+ <resources>
|
|
|
f778fe |
+ <bundle id="B1">
|
|
|
f778fe |
+ <meta_attributes id="B1-meta_attributes">
|
|
|
f778fe |
+
|
|
|
f778fe |
+ name="target-role" value="Stopped" />
|
|
|
f778fe |
+ </meta_attributes>
|
|
|
f778fe |
+ <docker image="pcs:test" masters="3" replicas="6"/>
|
|
|
f778fe |
+ </bundle>
|
|
|
f778fe |
+ </resources>
|
|
|
f778fe |
+ """
|
|
|
f778fe |
+
|
|
|
f778fe |
+ def test_add_meta_element(self):
|
|
|
f778fe |
+ self.assert_command_effect(
|
|
|
f778fe |
+ self.fixture_no_meta,
|
|
|
f778fe |
+ lambda: resource.bundle_update(
|
|
|
f778fe |
+ self.env, "B1",
|
|
|
f778fe |
+ meta_attributes={
|
|
|
f778fe |
+ "target-role": "Stopped",
|
|
|
f778fe |
+ }
|
|
|
f778fe |
+ ),
|
|
|
f778fe |
+ self.fixture_meta_stopped
|
|
|
f778fe |
+ )
|
|
|
f778fe |
+
|
|
|
f778fe |
+ def test_remove_meta_element(self):
|
|
|
f778fe |
+ self.assert_command_effect(
|
|
|
f778fe |
+ self.fixture_meta_stopped,
|
|
|
f778fe |
+ lambda: resource.bundle_update(
|
|
|
f778fe |
+ self.env, "B1",
|
|
|
f778fe |
+ meta_attributes={
|
|
|
f778fe |
+ "target-role": "",
|
|
|
f778fe |
+ }
|
|
|
f778fe |
+ ),
|
|
|
f778fe |
+ self.fixture_no_meta
|
|
|
f778fe |
+ )
|
|
|
f778fe |
+
|
|
|
f778fe |
+ def test_change_meta(self):
|
|
|
f778fe |
+ fixture_cib_pre = """
|
|
|
f778fe |
+ <resources>
|
|
|
f778fe |
+ <bundle id="B1">
|
|
|
f778fe |
+ <meta_attributes id="B1-meta_attributes">
|
|
|
f778fe |
+
|
|
|
f778fe |
+ name="target-role" value="Stopped" />
|
|
|
f778fe |
+
|
|
|
f778fe |
+ name="priority" value="15" />
|
|
|
f778fe |
+
|
|
|
f778fe |
+ name="is-managed" value="false" />
|
|
|
f778fe |
+ </meta_attributes>
|
|
|
f778fe |
+ <docker image="pcs:test" masters="3" replicas="6"/>
|
|
|
f778fe |
+ </bundle>
|
|
|
f778fe |
+ </resources>
|
|
|
f778fe |
+ """
|
|
|
f778fe |
+ fixture_cib_post = """
|
|
|
f778fe |
+ <resources>
|
|
|
f778fe |
+ <bundle id="B1">
|
|
|
f778fe |
+ <meta_attributes id="B1-meta_attributes">
|
|
|
f778fe |
+
|
|
|
f778fe |
+ name="target-role" value="Stopped" />
|
|
|
f778fe |
+
|
|
|
f778fe |
+ name="priority" value="10" />
|
|
|
f778fe |
+
|
|
|
f778fe |
+ name="resource-stickiness" value="100" />
|
|
|
f778fe |
+ </meta_attributes>
|
|
|
f778fe |
+ <docker image="pcs:test" masters="3" replicas="6"/>
|
|
|
f778fe |
+ </bundle>
|
|
|
f778fe |
+ </resources>
|
|
|
f778fe |
+ """
|
|
|
f778fe |
+ self.assert_command_effect(
|
|
|
f778fe |
+ fixture_cib_pre,
|
|
|
f778fe |
+ lambda: resource.bundle_update(
|
|
|
f778fe |
+ self.env, "B1",
|
|
|
f778fe |
+ meta_attributes={
|
|
|
f778fe |
+ "priority": "10",
|
|
|
f778fe |
+ "resource-stickiness": "100",
|
|
|
f778fe |
+ "is-managed": "",
|
|
|
f778fe |
+ }
|
|
|
f778fe |
+ ),
|
|
|
f778fe |
+ fixture_cib_post
|
|
|
f778fe |
+ )
|
|
|
f778fe |
+
|
|
|
f778fe |
+
|
|
|
f778fe |
class Wait(CommonTest):
|
|
|
f778fe |
fixture_status_running = """
|
|
|
f778fe |
<resources>
|
|
|
f778fe |
@@ -794,7 +884,7 @@ class Wait(CommonTest):
|
|
|
f778fe |
self.runner.assert_everything_launched()
|
|
|
f778fe |
|
|
|
f778fe |
@skip_unless_pacemaker_supports_bundle
|
|
|
f778fe |
- def test_wait_ok_run_ok(self):
|
|
|
f778fe |
+ def test_wait_ok_running(self):
|
|
|
f778fe |
self.runner.set_runs(
|
|
|
f778fe |
self.fixture_calls_initial() +
|
|
|
f778fe |
fixture.call_wait(self.timeout) +
|
|
|
f778fe |
@@ -811,7 +901,7 @@ class Wait(CommonTest):
|
|
|
f778fe |
self.runner.assert_everything_launched()
|
|
|
f778fe |
|
|
|
f778fe |
@skip_unless_pacemaker_supports_bundle
|
|
|
f778fe |
- def test_wait_ok_run_fail(self):
|
|
|
f778fe |
+ def test_wait_ok_not_running(self):
|
|
|
f778fe |
self.runner.set_runs(
|
|
|
f778fe |
self.fixture_calls_initial() +
|
|
|
f778fe |
fixture.call_wait(self.timeout) +
|
|
|
f778fe |
@@ -819,8 +909,8 @@ class Wait(CommonTest):
|
|
|
f778fe |
self.fixture_status_not_running
|
|
|
f778fe |
))
|
|
|
f778fe |
)
|
|
|
f778fe |
- assert_raise_library_error(
|
|
|
f778fe |
- lambda: self.simple_bundle_update(self.timeout),
|
|
|
f778fe |
- fixture.report_resource_not_running("B1", severities.ERROR),
|
|
|
f778fe |
- )
|
|
|
f778fe |
+ self.simple_bundle_update(self.timeout)
|
|
|
f778fe |
+ self.env.report_processor.assert_reports([
|
|
|
f778fe |
+ fixture.report_resource_not_running("B1", severities.INFO),
|
|
|
f778fe |
+ ])
|
|
|
f778fe |
self.runner.assert_everything_launched()
|
|
|
f778fe |
diff --git a/pcs/lib/commands/test/resource/test_resource_enable_disable.py b/pcs/lib/commands/test/resource/test_resource_enable_disable.py
|
|
|
f778fe |
index 91ac068..b03740b 100644
|
|
|
f778fe |
--- a/pcs/lib/commands/test/resource/test_resource_enable_disable.py
|
|
|
f778fe |
+++ b/pcs/lib/commands/test/resource/test_resource_enable_disable.py
|
|
|
f778fe |
@@ -469,6 +469,35 @@ fixture_bundle_cib_disabled_primitive = """
|
|
|
f778fe |
</bundle>
|
|
|
f778fe |
</resources>
|
|
|
f778fe |
"""
|
|
|
f778fe |
+fixture_bundle_cib_disabled_bundle = """
|
|
|
f778fe |
+ <resources>
|
|
|
f778fe |
+ <bundle id="A-bundle">
|
|
|
f778fe |
+ <meta_attributes id="A-bundle-meta_attributes">
|
|
|
f778fe |
+
|
|
|
f778fe |
+ name="target-role" value="Stopped" />
|
|
|
f778fe |
+ </meta_attributes>
|
|
|
f778fe |
+ <docker image="pcs:test" />
|
|
|
f778fe |
+ <primitive id="A" class="ocf" provider="heartbeat" type="Dummy" />
|
|
|
f778fe |
+ </bundle>
|
|
|
f778fe |
+ </resources>
|
|
|
f778fe |
+"""
|
|
|
f778fe |
+fixture_bundle_cib_disabled_both = """
|
|
|
f778fe |
+ <resources>
|
|
|
f778fe |
+ <bundle id="A-bundle">
|
|
|
f778fe |
+ <meta_attributes id="A-bundle-meta_attributes">
|
|
|
f778fe |
+
|
|
|
f778fe |
+ name="target-role" value="Stopped" />
|
|
|
f778fe |
+ </meta_attributes>
|
|
|
f778fe |
+ <docker image="pcs:test" />
|
|
|
f778fe |
+ <primitive id="A" class="ocf" provider="heartbeat" type="Dummy">
|
|
|
f778fe |
+ <meta_attributes id="A-meta_attributes">
|
|
|
f778fe |
+
|
|
|
f778fe |
+ name="target-role" value="Stopped" />
|
|
|
f778fe |
+ </meta_attributes>
|
|
|
f778fe |
+ </primitive>
|
|
|
f778fe |
+ </bundle>
|
|
|
f778fe |
+ </resources>
|
|
|
f778fe |
+"""
|
|
|
f778fe |
fixture_bundle_status_managed = """
|
|
|
f778fe |
<resources>
|
|
|
f778fe |
|
|
|
f778fe |
@@ -486,7 +515,7 @@ fixture_bundle_status_managed = """
|
|
|
f778fe |
fixture_bundle_status_unmanaged = """
|
|
|
f778fe |
<resources>
|
|
|
f778fe |
|
|
|
f778fe |
- unique="false" managed="true" failed="false"
|
|
|
f778fe |
+ unique="false" managed="false" failed="false"
|
|
|
f778fe |
>
|
|
|
f778fe |
<replica id="0">
|
|
|
f778fe |
<resource id="A" managed="false" />
|
|
|
f778fe |
@@ -1460,17 +1489,12 @@ class DisableBundle(ResourceWithStateTest):
|
|
|
f778fe |
)
|
|
|
f778fe |
|
|
|
f778fe |
def test_bundle(self):
|
|
|
f778fe |
- self.runner.set_runs(
|
|
|
f778fe |
- fixture.call_cib_load(
|
|
|
f778fe |
- fixture.cib_resources(fixture_bundle_cib_enabled)
|
|
|
f778fe |
- )
|
|
|
f778fe |
- )
|
|
|
f778fe |
-
|
|
|
f778fe |
- assert_raise_library_error(
|
|
|
f778fe |
+ self.assert_command_effect(
|
|
|
f778fe |
+ fixture_bundle_cib_enabled,
|
|
|
f778fe |
+ fixture_bundle_status_managed,
|
|
|
f778fe |
lambda: resource.disable(self.env, ["A-bundle"], False),
|
|
|
f778fe |
- fixture.report_not_for_bundles("A-bundle")
|
|
|
f778fe |
+ fixture_bundle_cib_disabled_bundle
|
|
|
f778fe |
)
|
|
|
f778fe |
- self.runner.assert_everything_launched()
|
|
|
f778fe |
|
|
|
f778fe |
def test_primitive_unmanaged(self):
|
|
|
f778fe |
self.assert_command_effect(
|
|
|
f778fe |
@@ -1483,6 +1507,17 @@ class DisableBundle(ResourceWithStateTest):
|
|
|
f778fe |
]
|
|
|
f778fe |
)
|
|
|
f778fe |
|
|
|
f778fe |
+ def test_bundle_unmanaged(self):
|
|
|
f778fe |
+ self.assert_command_effect(
|
|
|
f778fe |
+ fixture_bundle_cib_enabled,
|
|
|
f778fe |
+ fixture_bundle_status_unmanaged,
|
|
|
f778fe |
+ lambda: resource.disable(self.env, ["A-bundle"], False),
|
|
|
f778fe |
+ fixture_bundle_cib_disabled_bundle,
|
|
|
f778fe |
+ reports=[
|
|
|
f778fe |
+ fixture_report_unmanaged("A-bundle"),
|
|
|
f778fe |
+ ]
|
|
|
f778fe |
+ )
|
|
|
f778fe |
+
|
|
|
f778fe |
|
|
|
f778fe |
@skip_unless_pacemaker_supports_bundle
|
|
|
f778fe |
class EnableBundle(ResourceWithStateTest):
|
|
|
f778fe |
@@ -1494,18 +1529,29 @@ class EnableBundle(ResourceWithStateTest):
|
|
|
f778fe |
fixture_bundle_cib_enabled
|
|
|
f778fe |
)
|
|
|
f778fe |
|
|
|
f778fe |
+ def test_primitive_disabled_both(self):
|
|
|
f778fe |
+ self.assert_command_effect(
|
|
|
f778fe |
+ fixture_bundle_cib_disabled_both,
|
|
|
f778fe |
+ fixture_bundle_status_managed,
|
|
|
f778fe |
+ lambda: resource.enable(self.env, ["A"], False),
|
|
|
f778fe |
+ fixture_bundle_cib_enabled
|
|
|
f778fe |
+ )
|
|
|
f778fe |
+
|
|
|
f778fe |
def test_bundle(self):
|
|
|
f778fe |
- self.runner.set_runs(
|
|
|
f778fe |
- fixture.call_cib_load(
|
|
|
f778fe |
- fixture.cib_resources(fixture_bundle_cib_enabled)
|
|
|
f778fe |
- )
|
|
|
f778fe |
+ self.assert_command_effect(
|
|
|
f778fe |
+ fixture_bundle_cib_disabled_bundle,
|
|
|
f778fe |
+ fixture_bundle_status_managed,
|
|
|
f778fe |
+ lambda: resource.enable(self.env, ["A-bundle"], False),
|
|
|
f778fe |
+ fixture_bundle_cib_enabled
|
|
|
f778fe |
)
|
|
|
f778fe |
|
|
|
f778fe |
- assert_raise_library_error(
|
|
|
f778fe |
+ def test_bundle_disabled_both(self):
|
|
|
f778fe |
+ self.assert_command_effect(
|
|
|
f778fe |
+ fixture_bundle_cib_disabled_both,
|
|
|
f778fe |
+ fixture_bundle_status_managed,
|
|
|
f778fe |
lambda: resource.enable(self.env, ["A-bundle"], False),
|
|
|
f778fe |
- fixture.report_not_for_bundles("A-bundle")
|
|
|
f778fe |
+ fixture_bundle_cib_enabled
|
|
|
f778fe |
)
|
|
|
f778fe |
- self.runner.assert_everything_launched()
|
|
|
f778fe |
|
|
|
f778fe |
def test_primitive_unmanaged(self):
|
|
|
f778fe |
self.assert_command_effect(
|
|
|
f778fe |
@@ -1515,5 +1561,18 @@ class EnableBundle(ResourceWithStateTest):
|
|
|
f778fe |
fixture_bundle_cib_enabled,
|
|
|
f778fe |
reports=[
|
|
|
f778fe |
fixture_report_unmanaged("A"),
|
|
|
f778fe |
+ fixture_report_unmanaged("A-bundle"),
|
|
|
f778fe |
+ ]
|
|
|
f778fe |
+ )
|
|
|
f778fe |
+
|
|
|
f778fe |
+ def test_bundle_unmanaged(self):
|
|
|
f778fe |
+ self.assert_command_effect(
|
|
|
f778fe |
+ fixture_bundle_cib_disabled_primitive,
|
|
|
f778fe |
+ fixture_bundle_status_unmanaged,
|
|
|
f778fe |
+ lambda: resource.enable(self.env, ["A-bundle"], False),
|
|
|
f778fe |
+ fixture_bundle_cib_enabled,
|
|
|
f778fe |
+ reports=[
|
|
|
f778fe |
+ fixture_report_unmanaged("A-bundle"),
|
|
|
f778fe |
+ fixture_report_unmanaged("A"),
|
|
|
f778fe |
]
|
|
|
f778fe |
)
|
|
|
f778fe |
diff --git a/pcs/lib/commands/test/resource/test_resource_manage_unmanage.py b/pcs/lib/commands/test/resource/test_resource_manage_unmanage.py
|
|
|
f778fe |
index 6d8c787..95b44bc 100644
|
|
|
f778fe |
--- a/pcs/lib/commands/test/resource/test_resource_manage_unmanage.py
|
|
|
f778fe |
+++ b/pcs/lib/commands/test/resource/test_resource_manage_unmanage.py
|
|
|
f778fe |
@@ -517,6 +517,26 @@ fixture_clone_group_cib_unmanaged_all_primitives_op_disabled = """
|
|
|
f778fe |
</resources>
|
|
|
f778fe |
"""
|
|
|
f778fe |
|
|
|
f778fe |
+
|
|
|
f778fe |
+fixture_bundle_empty_cib_managed = """
|
|
|
f778fe |
+ <resources>
|
|
|
f778fe |
+ <bundle id="A-bundle">
|
|
|
f778fe |
+ <docker image="pcs:test" />
|
|
|
f778fe |
+ </bundle>
|
|
|
f778fe |
+ </resources>
|
|
|
f778fe |
+"""
|
|
|
f778fe |
+fixture_bundle_empty_cib_unmanaged_bundle = """
|
|
|
f778fe |
+ <resources>
|
|
|
f778fe |
+ <bundle id="A-bundle">
|
|
|
f778fe |
+ <meta_attributes id="A-bundle-meta_attributes">
|
|
|
f778fe |
+
|
|
|
f778fe |
+ name="is-managed" value="false" />
|
|
|
f778fe |
+ </meta_attributes>
|
|
|
f778fe |
+ <docker image="pcs:test" />
|
|
|
f778fe |
+ </bundle>
|
|
|
f778fe |
+ </resources>
|
|
|
f778fe |
+"""
|
|
|
f778fe |
+
|
|
|
f778fe |
fixture_bundle_cib_managed = """
|
|
|
f778fe |
<resources>
|
|
|
f778fe |
<bundle id="A-bundle">
|
|
|
f778fe |
@@ -526,7 +546,19 @@ fixture_bundle_cib_managed = """
|
|
|
f778fe |
</bundle>
|
|
|
f778fe |
</resources>
|
|
|
f778fe |
"""
|
|
|
f778fe |
-
|
|
|
f778fe |
+fixture_bundle_cib_unmanaged_bundle = """
|
|
|
f778fe |
+ <resources>
|
|
|
f778fe |
+ <bundle id="A-bundle">
|
|
|
f778fe |
+ <meta_attributes id="A-bundle-meta_attributes">
|
|
|
f778fe |
+
|
|
|
f778fe |
+ name="is-managed" value="false" />
|
|
|
f778fe |
+ </meta_attributes>
|
|
|
f778fe |
+ <docker image="pcs:test" />
|
|
|
f778fe |
+ <primitive id="A" class="ocf" provider="heartbeat" type="Dummy">
|
|
|
f778fe |
+ </primitive>
|
|
|
f778fe |
+ </bundle>
|
|
|
f778fe |
+ </resources>
|
|
|
f778fe |
+"""
|
|
|
f778fe |
fixture_bundle_cib_unmanaged_primitive = """
|
|
|
f778fe |
<resources>
|
|
|
f778fe |
<bundle id="A-bundle">
|
|
|
f778fe |
@@ -540,6 +572,78 @@ fixture_bundle_cib_unmanaged_primitive = """
|
|
|
f778fe |
</bundle>
|
|
|
f778fe |
</resources>
|
|
|
f778fe |
"""
|
|
|
f778fe |
+fixture_bundle_cib_unmanaged_both = """
|
|
|
f778fe |
+ <resources>
|
|
|
f778fe |
+ <bundle id="A-bundle">
|
|
|
f778fe |
+ <meta_attributes id="A-bundle-meta_attributes">
|
|
|
f778fe |
+
|
|
|
f778fe |
+ name="is-managed" value="false" />
|
|
|
f778fe |
+ </meta_attributes>
|
|
|
f778fe |
+ <docker image="pcs:test" />
|
|
|
f778fe |
+ <primitive id="A" class="ocf" provider="heartbeat" type="Dummy">
|
|
|
f778fe |
+ <meta_attributes id="A-meta_attributes">
|
|
|
f778fe |
+
|
|
|
f778fe |
+ name="is-managed" value="false" />
|
|
|
f778fe |
+ </meta_attributes>
|
|
|
f778fe |
+ </primitive>
|
|
|
f778fe |
+ </bundle>
|
|
|
f778fe |
+ </resources>
|
|
|
f778fe |
+"""
|
|
|
f778fe |
+
|
|
|
f778fe |
+fixture_bundle_cib_managed_op_enabled = """
|
|
|
f778fe |
+ <resources>
|
|
|
f778fe |
+ <bundle id="A-bundle">
|
|
|
f778fe |
+ <docker image="pcs:test" />
|
|
|
f778fe |
+ <primitive id="A" class="ocf" provider="heartbeat" type="Dummy">
|
|
|
f778fe |
+ <operations>
|
|
|
f778fe |
+ <op id="A-start" name="start" />
|
|
|
f778fe |
+ <op id="A-stop" name="stop" />
|
|
|
f778fe |
+ <op id="A-monitor" name="monitor"/>
|
|
|
f778fe |
+ </operations>
|
|
|
f778fe |
+ </primitive>
|
|
|
f778fe |
+ </bundle>
|
|
|
f778fe |
+ </resources>
|
|
|
f778fe |
+"""
|
|
|
f778fe |
+fixture_bundle_cib_unmanaged_primitive_op_disabled = """
|
|
|
f778fe |
+ <resources>
|
|
|
f778fe |
+ <bundle id="A-bundle">
|
|
|
f778fe |
+ <docker image="pcs:test" />
|
|
|
f778fe |
+ <primitive id="A" class="ocf" provider="heartbeat" type="Dummy">
|
|
|
f778fe |
+ <meta_attributes id="A-meta_attributes">
|
|
|
f778fe |
+
|
|
|
f778fe |
+ name="is-managed" value="false" />
|
|
|
f778fe |
+ </meta_attributes>
|
|
|
f778fe |
+ <operations>
|
|
|
f778fe |
+ <op id="A-start" name="start" />
|
|
|
f778fe |
+ <op id="A-stop" name="stop" />
|
|
|
f778fe |
+ <op id="A-monitor" name="monitor" enabled="false"/>
|
|
|
f778fe |
+ </operations>
|
|
|
f778fe |
+ </primitive>
|
|
|
f778fe |
+ </bundle>
|
|
|
f778fe |
+ </resources>
|
|
|
f778fe |
+"""
|
|
|
f778fe |
+fixture_bundle_cib_unmanaged_both_op_disabled = """
|
|
|
f778fe |
+ <resources>
|
|
|
f778fe |
+ <bundle id="A-bundle">
|
|
|
f778fe |
+ <meta_attributes id="A-bundle-meta_attributes">
|
|
|
f778fe |
+
|
|
|
f778fe |
+ name="is-managed" value="false" />
|
|
|
f778fe |
+ </meta_attributes>
|
|
|
f778fe |
+ <docker image="pcs:test" />
|
|
|
f778fe |
+ <primitive id="A" class="ocf" provider="heartbeat" type="Dummy">
|
|
|
f778fe |
+ <meta_attributes id="A-meta_attributes">
|
|
|
f778fe |
+
|
|
|
f778fe |
+ name="is-managed" value="false" />
|
|
|
f778fe |
+ </meta_attributes>
|
|
|
f778fe |
+ <operations>
|
|
|
f778fe |
+ <op id="A-start" name="start" />
|
|
|
f778fe |
+ <op id="A-stop" name="stop" />
|
|
|
f778fe |
+ <op id="A-monitor" name="monitor" enabled="false"/>
|
|
|
f778fe |
+ </operations>
|
|
|
f778fe |
+ </primitive>
|
|
|
f778fe |
+ </bundle>
|
|
|
f778fe |
+ </resources>
|
|
|
f778fe |
+"""
|
|
|
f778fe |
|
|
|
f778fe |
def fixture_report_no_monitors(resource):
|
|
|
f778fe |
return (
|
|
|
f778fe |
@@ -852,17 +956,18 @@ class UnmanageBundle(ResourceWithoutStateTest):
|
|
|
f778fe |
)
|
|
|
f778fe |
|
|
|
f778fe |
def test_bundle(self):
|
|
|
f778fe |
- self.runner.set_runs(
|
|
|
f778fe |
- fixture.call_cib_load(
|
|
|
f778fe |
- fixture.cib_resources(fixture_bundle_cib_managed)
|
|
|
f778fe |
- )
|
|
|
f778fe |
+ self.assert_command_effect(
|
|
|
f778fe |
+ fixture_bundle_cib_managed,
|
|
|
f778fe |
+ lambda: resource.unmanage(self.env, ["A-bundle"]),
|
|
|
f778fe |
+ fixture_bundle_cib_unmanaged_both
|
|
|
f778fe |
)
|
|
|
f778fe |
|
|
|
f778fe |
- assert_raise_library_error(
|
|
|
f778fe |
- lambda: resource.unmanage(self.env, ["A-bundle"], False),
|
|
|
f778fe |
- fixture.report_not_for_bundles("A-bundle")
|
|
|
f778fe |
+ def test_bundle_empty(self):
|
|
|
f778fe |
+ self.assert_command_effect(
|
|
|
f778fe |
+ fixture_bundle_empty_cib_managed,
|
|
|
f778fe |
+ lambda: resource.unmanage(self.env, ["A-bundle"]),
|
|
|
f778fe |
+ fixture_bundle_empty_cib_unmanaged_bundle
|
|
|
f778fe |
)
|
|
|
f778fe |
- self.runner.assert_everything_launched()
|
|
|
f778fe |
|
|
|
f778fe |
|
|
|
f778fe |
class ManageBundle(ResourceWithoutStateTest):
|
|
|
f778fe |
@@ -873,18 +978,47 @@ class ManageBundle(ResourceWithoutStateTest):
|
|
|
f778fe |
fixture_bundle_cib_managed,
|
|
|
f778fe |
)
|
|
|
f778fe |
|
|
|
f778fe |
+ def test_primitive_unmanaged_bundle(self):
|
|
|
f778fe |
+ self.assert_command_effect(
|
|
|
f778fe |
+ fixture_bundle_cib_unmanaged_bundle,
|
|
|
f778fe |
+ lambda: resource.manage(self.env, ["A"]),
|
|
|
f778fe |
+ fixture_bundle_cib_managed,
|
|
|
f778fe |
+ )
|
|
|
f778fe |
+
|
|
|
f778fe |
+ def test_primitive_unmanaged_both(self):
|
|
|
f778fe |
+ self.assert_command_effect(
|
|
|
f778fe |
+ fixture_bundle_cib_unmanaged_both,
|
|
|
f778fe |
+ lambda: resource.manage(self.env, ["A"]),
|
|
|
f778fe |
+ fixture_bundle_cib_managed,
|
|
|
f778fe |
+ )
|
|
|
f778fe |
+
|
|
|
f778fe |
def test_bundle(self):
|
|
|
f778fe |
- self.runner.set_runs(
|
|
|
f778fe |
- fixture.call_cib_load(
|
|
|
f778fe |
- fixture.cib_resources(fixture_bundle_cib_unmanaged_primitive)
|
|
|
f778fe |
- )
|
|
|
f778fe |
+ self.assert_command_effect(
|
|
|
f778fe |
+ fixture_bundle_cib_unmanaged_bundle,
|
|
|
f778fe |
+ lambda: resource.manage(self.env, ["A-bundle"]),
|
|
|
f778fe |
+ fixture_bundle_cib_managed,
|
|
|
f778fe |
)
|
|
|
f778fe |
|
|
|
f778fe |
- assert_raise_library_error(
|
|
|
f778fe |
- lambda: resource.manage(self.env, ["A-bundle"], False),
|
|
|
f778fe |
- fixture.report_not_for_bundles("A-bundle")
|
|
|
f778fe |
+ def test_bundle_unmanaged_primitive(self):
|
|
|
f778fe |
+ self.assert_command_effect(
|
|
|
f778fe |
+ fixture_bundle_cib_unmanaged_primitive,
|
|
|
f778fe |
+ lambda: resource.manage(self.env, ["A-bundle"]),
|
|
|
f778fe |
+ fixture_bundle_cib_managed,
|
|
|
f778fe |
+ )
|
|
|
f778fe |
+
|
|
|
f778fe |
+ def test_bundle_unmanaged_both(self):
|
|
|
f778fe |
+ self.assert_command_effect(
|
|
|
f778fe |
+ fixture_bundle_cib_unmanaged_both,
|
|
|
f778fe |
+ lambda: resource.manage(self.env, ["A-bundle"]),
|
|
|
f778fe |
+ fixture_bundle_cib_managed,
|
|
|
f778fe |
+ )
|
|
|
f778fe |
+
|
|
|
f778fe |
+ def test_bundle_empty(self):
|
|
|
f778fe |
+ self.assert_command_effect(
|
|
|
f778fe |
+ fixture_bundle_empty_cib_unmanaged_bundle,
|
|
|
f778fe |
+ lambda: resource.manage(self.env, ["A-bundle"]),
|
|
|
f778fe |
+ fixture_bundle_empty_cib_managed
|
|
|
f778fe |
)
|
|
|
f778fe |
- self.runner.assert_everything_launched()
|
|
|
f778fe |
|
|
|
f778fe |
|
|
|
f778fe |
class MoreResources(ResourceWithoutStateTest):
|
|
|
f778fe |
@@ -1090,3 +1224,24 @@ class WithMonitor(ResourceWithoutStateTest):
|
|
|
f778fe |
lambda: resource.unmanage(self.env, ["A1"], True),
|
|
|
f778fe |
fixture_clone_group_cib_unmanaged_primitive_op_disabled
|
|
|
f778fe |
)
|
|
|
f778fe |
+
|
|
|
f778fe |
+ def test_unmanage_bundle(self):
|
|
|
f778fe |
+ self.assert_command_effect(
|
|
|
f778fe |
+ fixture_bundle_cib_managed_op_enabled,
|
|
|
f778fe |
+ lambda: resource.unmanage(self.env, ["A-bundle"], True),
|
|
|
f778fe |
+ fixture_bundle_cib_unmanaged_both_op_disabled
|
|
|
f778fe |
+ )
|
|
|
f778fe |
+
|
|
|
f778fe |
+ def test_unmanage_in_bundle(self):
|
|
|
f778fe |
+ self.assert_command_effect(
|
|
|
f778fe |
+ fixture_bundle_cib_managed_op_enabled,
|
|
|
f778fe |
+ lambda: resource.unmanage(self.env, ["A"], True),
|
|
|
f778fe |
+ fixture_bundle_cib_unmanaged_primitive_op_disabled
|
|
|
f778fe |
+ )
|
|
|
f778fe |
+
|
|
|
f778fe |
+ def test_unmanage_bundle_empty(self):
|
|
|
f778fe |
+ self.assert_command_effect(
|
|
|
f778fe |
+ fixture_bundle_empty_cib_managed,
|
|
|
f778fe |
+ lambda: resource.unmanage(self.env, ["A-bundle"], True),
|
|
|
f778fe |
+ fixture_bundle_empty_cib_unmanaged_bundle
|
|
|
f778fe |
+ )
|
|
|
f778fe |
diff --git a/pcs/lib/pacemaker/state.py b/pcs/lib/pacemaker/state.py
|
|
|
f778fe |
index 71809db..be3e7ad 100644
|
|
|
f778fe |
--- a/pcs/lib/pacemaker/state.py
|
|
|
f778fe |
+++ b/pcs/lib/pacemaker/state.py
|
|
|
f778fe |
@@ -201,6 +201,25 @@ def _get_primitive_roles_with_nodes(primitive_el_list):
|
|
|
f778fe |
for role, nodes in roles_with_nodes.items()
|
|
|
f778fe |
])
|
|
|
f778fe |
|
|
|
f778fe |
+def info_resource_state(cluster_state, resource_id):
|
|
|
f778fe |
+ roles_with_nodes = _get_primitive_roles_with_nodes(
|
|
|
f778fe |
+ _get_primitives_for_state_check(
|
|
|
f778fe |
+ cluster_state,
|
|
|
f778fe |
+ resource_id,
|
|
|
f778fe |
+ expected_running=True
|
|
|
f778fe |
+ )
|
|
|
f778fe |
+ )
|
|
|
f778fe |
+ if not roles_with_nodes:
|
|
|
f778fe |
+ return reports.resource_does_not_run(
|
|
|
f778fe |
+ resource_id,
|
|
|
f778fe |
+ severities.INFO
|
|
|
f778fe |
+ )
|
|
|
f778fe |
+ return reports.resource_running_on_nodes(
|
|
|
f778fe |
+ resource_id,
|
|
|
f778fe |
+ roles_with_nodes,
|
|
|
f778fe |
+ severities.INFO
|
|
|
f778fe |
+ )
|
|
|
f778fe |
+
|
|
|
f778fe |
def ensure_resource_state(expected_running, cluster_state, resource_id):
|
|
|
f778fe |
roles_with_nodes = _get_primitive_roles_with_nodes(
|
|
|
f778fe |
_get_primitives_for_state_check(
|
|
|
f778fe |
@@ -244,18 +263,25 @@ def is_resource_managed(cluster_state, resource_id):
|
|
|
f778fe |
for primitive in primitive_list:
|
|
|
f778fe |
if is_false(primitive.attrib.get("managed", "")):
|
|
|
f778fe |
return False
|
|
|
f778fe |
- clone = find_parent(primitive, ["clone"])
|
|
|
f778fe |
- if clone is not None and is_false(clone.attrib.get("managed", "")):
|
|
|
f778fe |
+ parent = find_parent(primitive, ["clone", "bundle"])
|
|
|
f778fe |
+ if (
|
|
|
f778fe |
+ parent is not None
|
|
|
f778fe |
+ and
|
|
|
f778fe |
+ is_false(parent.attrib.get("managed", ""))
|
|
|
f778fe |
+ ):
|
|
|
f778fe |
return False
|
|
|
f778fe |
return True
|
|
|
f778fe |
|
|
|
f778fe |
- clone_list = cluster_state.xpath(
|
|
|
f778fe |
- """.//clone[@id="{0}"]""".format(resource_id)
|
|
|
f778fe |
+ parent_list = cluster_state.xpath("""
|
|
|
f778fe |
+ .//clone[@id="{0}"]
|
|
|
f778fe |
+ |
|
|
|
f778fe |
+ .//bundle[@id="{0}"]
|
|
|
f778fe |
+ """.format(resource_id)
|
|
|
f778fe |
)
|
|
|
f778fe |
- for clone in clone_list:
|
|
|
f778fe |
- if is_false(clone.attrib.get("managed", "")):
|
|
|
f778fe |
+ for parent in parent_list:
|
|
|
f778fe |
+ if is_false(parent.attrib.get("managed", "")):
|
|
|
f778fe |
return False
|
|
|
f778fe |
- for primitive in clone.xpath(".//resource"):
|
|
|
f778fe |
+ for primitive in parent.xpath(".//resource"):
|
|
|
f778fe |
if is_false(primitive.attrib.get("managed", "")):
|
|
|
f778fe |
return False
|
|
|
f778fe |
return True
|
|
|
f778fe |
diff --git a/pcs/lib/pacemaker/test/test_state.py b/pcs/lib/pacemaker/test/test_state.py
|
|
|
f778fe |
index a29eddf..5de9426 100644
|
|
|
f778fe |
--- a/pcs/lib/pacemaker/test/test_state.py
|
|
|
f778fe |
+++ b/pcs/lib/pacemaker/test/test_state.py
|
|
|
f778fe |
@@ -491,7 +491,7 @@ class GetPrimitivesForStateCheck(TestCase):
|
|
|
f778fe |
self.assert_primitives("B2-R2", ["B2-R2", "B2-R2"], False)
|
|
|
f778fe |
|
|
|
f778fe |
|
|
|
f778fe |
-class EnsureResourceState(TestCase):
|
|
|
f778fe |
+class CommonResourceState(TestCase):
|
|
|
f778fe |
resource_id = "R"
|
|
|
f778fe |
def setUp(self):
|
|
|
f778fe |
self.cluster_state = "state"
|
|
|
f778fe |
@@ -526,6 +526,8 @@ class EnsureResourceState(TestCase):
|
|
|
f778fe |
"resource_id": self.resource_id
|
|
|
f778fe |
})
|
|
|
f778fe |
|
|
|
f778fe |
+
|
|
|
f778fe |
+class EnsureResourceState(CommonResourceState):
|
|
|
f778fe |
def assert_running_info_transform(self, run_info, report, expected_running):
|
|
|
f778fe |
self.get_primitives_for_state_check.return_value = ["elem1", "elem2"]
|
|
|
f778fe |
self.get_primitive_roles_with_nodes.return_value = run_info
|
|
|
f778fe |
@@ -575,6 +577,35 @@ class EnsureResourceState(TestCase):
|
|
|
f778fe |
)
|
|
|
f778fe |
|
|
|
f778fe |
|
|
|
f778fe |
+class InfoResourceState(CommonResourceState):
|
|
|
f778fe |
+ def assert_running_info_transform(self, run_info, report):
|
|
|
f778fe |
+ self.get_primitives_for_state_check.return_value = ["elem1", "elem2"]
|
|
|
f778fe |
+ self.get_primitive_roles_with_nodes.return_value = run_info
|
|
|
f778fe |
+ assert_report_item_equal(
|
|
|
f778fe |
+ state.info_resource_state(self.cluster_state, self.resource_id),
|
|
|
f778fe |
+ report
|
|
|
f778fe |
+ )
|
|
|
f778fe |
+ self.get_primitives_for_state_check.assert_called_once_with(
|
|
|
f778fe |
+ self.cluster_state,
|
|
|
f778fe |
+ self.resource_id,
|
|
|
f778fe |
+ expected_running=True
|
|
|
f778fe |
+ )
|
|
|
f778fe |
+ self.get_primitive_roles_with_nodes.assert_called_once_with(
|
|
|
f778fe |
+ ["elem1", "elem2"]
|
|
|
f778fe |
+ )
|
|
|
f778fe |
+
|
|
|
f778fe |
+ def test_report_info_running(self):
|
|
|
f778fe |
+ self.assert_running_info_transform(
|
|
|
f778fe |
+ self.fixture_running_state_info(),
|
|
|
f778fe |
+ self.fixture_running_report(severities.INFO)
|
|
|
f778fe |
+ )
|
|
|
f778fe |
+ def test_report_info_not_running(self):
|
|
|
f778fe |
+ self.assert_running_info_transform(
|
|
|
f778fe |
+ [],
|
|
|
f778fe |
+ self.fixture_not_running_report(severities.INFO)
|
|
|
f778fe |
+ )
|
|
|
f778fe |
+
|
|
|
f778fe |
+
|
|
|
f778fe |
class IsResourceManaged(TestCase):
|
|
|
f778fe |
status_xml = etree.fromstring("""
|
|
|
f778fe |
<resources>
|
|
|
f778fe |
@@ -733,6 +764,60 @@ class IsResourceManaged(TestCase):
|
|
|
f778fe |
<resource id="R38:1" managed="false" />
|
|
|
f778fe |
</group>
|
|
|
f778fe |
</clone>
|
|
|
f778fe |
+
|
|
|
f778fe |
+ <bundle id="B1" managed="true" />
|
|
|
f778fe |
+ <bundle id="B2" managed="false" />
|
|
|
f778fe |
+
|
|
|
f778fe |
+ <bundle id="B3" managed="true">
|
|
|
f778fe |
+ <replica id="0">
|
|
|
f778fe |
+ <resource id="R39" managed="true" />
|
|
|
f778fe |
+ <resource id="R40" managed="true" />
|
|
|
f778fe |
+ </replica>
|
|
|
f778fe |
+ <replica id="1">
|
|
|
f778fe |
+ <resource id="R39" managed="true" />
|
|
|
f778fe |
+ <resource id="R40" managed="true" />
|
|
|
f778fe |
+ </replica>
|
|
|
f778fe |
+ </bundle>
|
|
|
f778fe |
+ <bundle id="B4" managed="false">
|
|
|
f778fe |
+ <replica id="0">
|
|
|
f778fe |
+ <resource id="R41" managed="true" />
|
|
|
f778fe |
+ <resource id="R42" managed="true" />
|
|
|
f778fe |
+ </replica>
|
|
|
f778fe |
+ <replica id="1">
|
|
|
f778fe |
+ <resource id="R41" managed="true" />
|
|
|
f778fe |
+ <resource id="R42" managed="true" />
|
|
|
f778fe |
+ </replica>
|
|
|
f778fe |
+ </bundle>
|
|
|
f778fe |
+ <bundle id="B5" managed="true">
|
|
|
f778fe |
+ <replica id="0">
|
|
|
f778fe |
+ <resource id="R43" managed="false" />
|
|
|
f778fe |
+ <resource id="R44" managed="true" />
|
|
|
f778fe |
+ </replica>
|
|
|
f778fe |
+ <replica id="1">
|
|
|
f778fe |
+ <resource id="R43" managed="false" />
|
|
|
f778fe |
+ <resource id="R44" managed="true" />
|
|
|
f778fe |
+ </replica>
|
|
|
f778fe |
+ </bundle>
|
|
|
f778fe |
+ <bundle id="B6" managed="true">
|
|
|
f778fe |
+ <replica id="0">
|
|
|
f778fe |
+ <resource id="R45" managed="true" />
|
|
|
f778fe |
+ <resource id="R46" managed="false" />
|
|
|
f778fe |
+ </replica>
|
|
|
f778fe |
+ <replica id="1">
|
|
|
f778fe |
+ <resource id="R45" managed="true" />
|
|
|
f778fe |
+ <resource id="R46" managed="false" />
|
|
|
f778fe |
+ </replica>
|
|
|
f778fe |
+ </bundle>
|
|
|
f778fe |
+ <bundle id="B7" managed="false">
|
|
|
f778fe |
+ <replica id="0">
|
|
|
f778fe |
+ <resource id="R47" managed="false" />
|
|
|
f778fe |
+ <resource id="R48" managed="false" />
|
|
|
f778fe |
+ </replica>
|
|
|
f778fe |
+ <replica id="1">
|
|
|
f778fe |
+ <resource id="R47" managed="false" />
|
|
|
f778fe |
+ <resource id="R48" managed="false" />
|
|
|
f778fe |
+ </replica>
|
|
|
f778fe |
+ </bundle>
|
|
|
f778fe |
</resources>
|
|
|
f778fe |
""")
|
|
|
f778fe |
|
|
|
f778fe |
@@ -856,3 +941,24 @@ class IsResourceManaged(TestCase):
|
|
|
f778fe |
self.assert_managed("R36", False)
|
|
|
f778fe |
self.assert_managed("R37", False)
|
|
|
f778fe |
self.assert_managed("R38", False)
|
|
|
f778fe |
+
|
|
|
f778fe |
+ def test_bundle(self):
|
|
|
f778fe |
+ self.assert_managed("B1", True)
|
|
|
f778fe |
+ self.assert_managed("B2", False)
|
|
|
f778fe |
+ self.assert_managed("B3", True)
|
|
|
f778fe |
+ self.assert_managed("B4", False)
|
|
|
f778fe |
+ self.assert_managed("B5", False)
|
|
|
f778fe |
+ self.assert_managed("B6", False)
|
|
|
f778fe |
+ self.assert_managed("B7", False)
|
|
|
f778fe |
+
|
|
|
f778fe |
+ def test_primitive_in_bundle(self):
|
|
|
f778fe |
+ self.assert_managed("R39", True)
|
|
|
f778fe |
+ self.assert_managed("R40", True)
|
|
|
f778fe |
+ self.assert_managed("R41", False)
|
|
|
f778fe |
+ self.assert_managed("R42", False)
|
|
|
f778fe |
+ self.assert_managed("R43", False)
|
|
|
f778fe |
+ self.assert_managed("R44", True)
|
|
|
f778fe |
+ self.assert_managed("R45", True)
|
|
|
f778fe |
+ self.assert_managed("R46", False)
|
|
|
f778fe |
+ self.assert_managed("R47", False)
|
|
|
f778fe |
+ self.assert_managed("R48", False)
|
|
|
f778fe |
diff --git a/pcs/pcs.8 b/pcs/pcs.8
|
|
|
f778fe |
index 446e7b3..20b5c2e 100644
|
|
|
f778fe |
--- a/pcs/pcs.8
|
|
|
f778fe |
+++ b/pcs/pcs.8
|
|
|
f778fe |
@@ -162,10 +162,10 @@ Remove the clone which contains the specified group or resource (the resource or
|
|
|
f778fe |
master [<master/slave id>] <resource id | group id> [options] [\fB\-\-wait\fR[=n]]
|
|
|
f778fe |
Configure a resource or group as a multi\-state (master/slave) resource. If \fB\-\-wait\fR is specified, pcs will wait up to 'n' seconds for the operation to finish (including starting and promoting resource instances if appropriate) and then return 0 on success or 1 on error. If 'n' is not specified it defaults to 60 minutes. Note: to remove a master you must remove the resource/group it contains.
|
|
|
f778fe |
.TP
|
|
|
f778fe |
-bundle create <bundle id> [container [<container type>] <container options>] [network <network options>] [port\-map <port options>]... [storage\-map <storage options>]... [\fB\-\-wait\fR[=n]]
|
|
|
f778fe |
-Create a new bundle encapsulating no resources. The bundle can be used either as it is or a resource may be put into it at any time. If the container type is not specified, it defaults to 'docker'. If \fB\-\-wait\fR is specified, pcs will wait up to 'n' seconds for the bundle to start and then return 0 on success or 1 on error. If 'n' is not specified it defaults to 60 minutes.
|
|
|
f778fe |
+bundle create <bundle id> [container [<container type>] <container options>] [network <network options>] [port\-map <port options>]... [storage\-map <storage options>]... [meta <meta options>] [\fB\-\-disabled\fR] [\fB\-\-wait\fR[=n]]
|
|
|
f778fe |
+Create a new bundle encapsulating no resources. The bundle can be used either as it is or a resource may be put into it at any time. If the container type is not specified, it defaults to 'docker'. If \fB\-\-disabled\fR is specified, the bundle is not started automatically. If \fB\-\-wait\fR is specified, pcs will wait up to 'n' seconds for the bundle to start and then return 0 on success or 1 on error. If 'n' is not specified it defaults to 60 minutes.
|
|
|
f778fe |
.TP
|
|
|
f778fe |
-bundle update <bundle id> [container <container options>] [network <network options>] [port\-map (add <port options>) | (remove <id>...)]... [storage\-map (add <storage options>) | (remove <id>...)]... [\fB\-\-wait\fR[=n]]
|
|
|
f778fe |
+bundle update <bundle id> [container <container options>] [network <network options>] [port\-map (add <port options>) | (remove <id>...)]... [storage\-map (add <storage options>) | (remove <id>...)]... [meta <meta options>] [\fB\-\-wait\fR[=n]]
|
|
|
f778fe |
Add, remove or change options to specified bundle. If you wish to update a resource encapsulated in the bundle, use the 'pcs resource update' command instead and specify the resource id. If \fB\-\-wait\fR is specified, pcs will wait up to 'n' seconds for the operation to finish (including moving resources if appropriate) and then return 0 on success or 1 on error. If 'n' is not specified it defaults to 60 minutes.
|
|
|
f778fe |
.TP
|
|
|
f778fe |
manage <resource id>... [\fB\-\-monitor\fR]
|
|
|
f778fe |
diff --git a/pcs/resource.py b/pcs/resource.py
|
|
|
f778fe |
index dc6da13..467faa5 100644
|
|
|
f778fe |
--- a/pcs/resource.py
|
|
|
f778fe |
+++ b/pcs/resource.py
|
|
|
f778fe |
@@ -20,7 +20,7 @@ from pcs import (
|
|
|
f778fe |
)
|
|
|
f778fe |
from pcs.settings import pacemaker_wait_timeout_status as \
|
|
|
f778fe |
PACEMAKER_WAIT_TIMEOUT_STATUS
|
|
|
f778fe |
-import pcs.lib.cib.acl as lib_acl
|
|
|
f778fe |
+from pcs.cli.common.console_report import error, warn
|
|
|
f778fe |
from pcs.cli.common.errors import CmdLineInputError
|
|
|
f778fe |
from pcs.cli.common.parse_args import prepare_options
|
|
|
f778fe |
from pcs.cli.resource.parse_args import (
|
|
|
f778fe |
@@ -28,16 +28,21 @@ from pcs.cli.resource.parse_args import (
|
|
|
f778fe |
parse_bundle_update_options,
|
|
|
f778fe |
parse_create as parse_create_args,
|
|
|
f778fe |
)
|
|
|
f778fe |
-from pcs.lib.errors import LibraryError
|
|
|
f778fe |
+import pcs.lib.cib.acl as lib_acl
|
|
|
f778fe |
from pcs.lib.cib.resource import guest_node
|
|
|
f778fe |
-import pcs.lib.pacemaker.live as lib_pacemaker
|
|
|
f778fe |
-from pcs.lib.pacemaker.values import timeout_to_seconds
|
|
|
f778fe |
-import pcs.lib.resource_agent as lib_ra
|
|
|
f778fe |
-from pcs.cli.common.console_report import error, warn
|
|
|
f778fe |
from pcs.lib.commands.resource import(
|
|
|
f778fe |
_validate_guest_change,
|
|
|
f778fe |
_get_nodes_to_validate_against,
|
|
|
f778fe |
)
|
|
|
f778fe |
+from pcs.lib.errors import LibraryError
|
|
|
f778fe |
+import pcs.lib.pacemaker.live as lib_pacemaker
|
|
|
f778fe |
+from pcs.lib.pacemaker.state import (
|
|
|
f778fe |
+ get_cluster_state_dom,
|
|
|
f778fe |
+ _get_primitive_roles_with_nodes,
|
|
|
f778fe |
+ _get_primitives_for_state_check,
|
|
|
f778fe |
+)
|
|
|
f778fe |
+from pcs.lib.pacemaker.values import timeout_to_seconds
|
|
|
f778fe |
+import pcs.lib.resource_agent as lib_ra
|
|
|
f778fe |
|
|
|
f778fe |
|
|
|
f778fe |
RESOURCE_RELOCATE_CONSTRAINT_PREFIX = "pcs-relocate-"
|
|
|
f778fe |
@@ -1432,6 +1437,18 @@ def resource_master_create(dom, argv, update=False, master_id=None):
|
|
|
f778fe |
return dom, master_element.getAttribute("id")
|
|
|
f778fe |
|
|
|
f778fe |
def resource_remove(resource_id, output=True, is_remove_remote_context=False):
|
|
|
f778fe |
+ def is_bundle_running(bundle_id):
|
|
|
f778fe |
+ roles_with_nodes = _get_primitive_roles_with_nodes(
|
|
|
f778fe |
+ _get_primitives_for_state_check(
|
|
|
f778fe |
+ get_cluster_state_dom(
|
|
|
f778fe |
+ lib_pacemaker.get_cluster_status_xml(utils.cmd_runner())
|
|
|
f778fe |
+ ),
|
|
|
f778fe |
+ bundle_id,
|
|
|
f778fe |
+ expected_running=True
|
|
|
f778fe |
+ )
|
|
|
f778fe |
+ )
|
|
|
f778fe |
+ return True if roles_with_nodes else False
|
|
|
f778fe |
+
|
|
|
f778fe |
dom = utils.get_cib_dom()
|
|
|
f778fe |
# if resource is a clone or a master, work with its child instead
|
|
|
f778fe |
cloned_resource = utils.dom_get_clone_ms_resource(dom, resource_id)
|
|
|
f778fe |
@@ -1441,6 +1458,40 @@ def resource_remove(resource_id, output=True, is_remove_remote_context=False):
|
|
|
f778fe |
bundle = utils.dom_get_bundle(dom, resource_id)
|
|
|
f778fe |
if bundle is not None:
|
|
|
f778fe |
primitive_el = utils.dom_get_resource_bundle(bundle)
|
|
|
f778fe |
+ if primitive_el is None:
|
|
|
f778fe |
+ print("Deleting bundle '{0}'".format(resource_id))
|
|
|
f778fe |
+ else:
|
|
|
f778fe |
+ print(
|
|
|
f778fe |
+ "Deleting bundle '{0}' and its inner resource '{1}'".format(
|
|
|
f778fe |
+ resource_id,
|
|
|
f778fe |
+ primitive_el.getAttribute("id")
|
|
|
f778fe |
+ )
|
|
|
f778fe |
+ )
|
|
|
f778fe |
+
|
|
|
f778fe |
+ if (
|
|
|
f778fe |
+ "--force" not in utils.pcs_options
|
|
|
f778fe |
+ and
|
|
|
f778fe |
+ not utils.usefile
|
|
|
f778fe |
+ and
|
|
|
f778fe |
+ is_bundle_running(resource_id)
|
|
|
f778fe |
+ ):
|
|
|
f778fe |
+ sys.stdout.write("Stopping bundle '{0}'... ".format(resource_id))
|
|
|
f778fe |
+ sys.stdout.flush()
|
|
|
f778fe |
+ lib = utils.get_library_wrapper()
|
|
|
f778fe |
+ lib.resource.disable([resource_id], False)
|
|
|
f778fe |
+ output, retval = utils.run(["crm_resource", "--wait"])
|
|
|
f778fe |
+ # pacemaker which supports bundles supports --wait as well
|
|
|
f778fe |
+ if is_bundle_running(resource_id):
|
|
|
f778fe |
+ msg = [
|
|
|
f778fe |
+ "Unable to stop: %s before deleting "
|
|
|
f778fe |
+ "(re-run with --force to force deletion)"
|
|
|
f778fe |
+ % resource_id
|
|
|
f778fe |
+ ]
|
|
|
f778fe |
+ if retval != 0 and output:
|
|
|
f778fe |
+ msg.append("\n" + output)
|
|
|
f778fe |
+ utils.err("\n".join(msg).strip())
|
|
|
f778fe |
+ print("Stopped")
|
|
|
f778fe |
+
|
|
|
f778fe |
if primitive_el is not None:
|
|
|
f778fe |
resource_remove(primitive_el.getAttribute("id"))
|
|
|
f778fe |
utils.replace_cib_configuration(
|
|
|
f778fe |
@@ -1498,7 +1549,7 @@ def resource_remove(resource_id, output=True, is_remove_remote_context=False):
|
|
|
f778fe |
resource_remove(res.getAttribute("id"))
|
|
|
f778fe |
sys.exit(0)
|
|
|
f778fe |
|
|
|
f778fe |
- # now we know resource is not a group, a clone nor a master
|
|
|
f778fe |
+ # now we know resource is not a group, a clone, a master nor a bundle
|
|
|
f778fe |
# because of the conditions above
|
|
|
f778fe |
if not utils.does_exist('//resources/descendant::primitive[@id="'+resource_id+'"]'):
|
|
|
f778fe |
utils.err("Resource '{0}' does not exist.".format(resource_id))
|
|
|
f778fe |
@@ -1517,7 +1568,7 @@ def resource_remove(resource_id, output=True, is_remove_remote_context=False):
|
|
|
f778fe |
and
|
|
|
f778fe |
utils.resource_running_on(resource_id)["is_running"]
|
|
|
f778fe |
):
|
|
|
f778fe |
- sys.stdout.write("Attempting to stop: "+ resource_id + "...")
|
|
|
f778fe |
+ sys.stdout.write("Attempting to stop: "+ resource_id + "... ")
|
|
|
f778fe |
sys.stdout.flush()
|
|
|
f778fe |
lib = utils.get_library_wrapper()
|
|
|
f778fe |
# we are not using wait from disable command, because if wait is not
|
|
|
f778fe |
@@ -2246,6 +2297,7 @@ def print_node(node, tab = 0):
|
|
|
f778fe |
node.findall("storage/storage-mapping"),
|
|
|
f778fe |
spaces + " "
|
|
|
f778fe |
)
|
|
|
f778fe |
+ print_meta_vars_string(node, spaces)
|
|
|
f778fe |
for child in node:
|
|
|
f778fe |
print_node(child, tab + 1)
|
|
|
f778fe |
return
|
|
|
f778fe |
@@ -2675,12 +2727,14 @@ def resource_bundle_create_cmd(lib, argv, modifiers):
|
|
|
f778fe |
lib.resource.bundle_create(
|
|
|
f778fe |
bundle_id,
|
|
|
f778fe |
parts["container_type"],
|
|
|
f778fe |
- parts["container"],
|
|
|
f778fe |
- parts["network"],
|
|
|
f778fe |
- parts["port_map"],
|
|
|
f778fe |
- parts["storage_map"],
|
|
|
f778fe |
- modifiers["force"],
|
|
|
f778fe |
- modifiers["wait"]
|
|
|
f778fe |
+ container_options=parts["container"],
|
|
|
f778fe |
+ network_options=parts["network"],
|
|
|
f778fe |
+ port_map=parts["port_map"],
|
|
|
f778fe |
+ storage_map=parts["storage_map"],
|
|
|
f778fe |
+ meta_attributes=parts["meta"],
|
|
|
f778fe |
+ force_options=modifiers["force"],
|
|
|
f778fe |
+ ensure_disabled=modifiers["disabled"],
|
|
|
f778fe |
+ wait=modifiers["wait"]
|
|
|
f778fe |
)
|
|
|
f778fe |
|
|
|
f778fe |
def resource_bundle_update_cmd(lib, argv, modifiers):
|
|
|
f778fe |
@@ -2691,12 +2745,13 @@ def resource_bundle_update_cmd(lib, argv, modifiers):
|
|
|
f778fe |
parts = parse_bundle_update_options(argv[1:])
|
|
|
f778fe |
lib.resource.bundle_update(
|
|
|
f778fe |
bundle_id,
|
|
|
f778fe |
- parts["container"],
|
|
|
f778fe |
- parts["network"],
|
|
|
f778fe |
- parts["port_map_add"],
|
|
|
f778fe |
- parts["port_map_remove"],
|
|
|
f778fe |
- parts["storage_map_add"],
|
|
|
f778fe |
- parts["storage_map_remove"],
|
|
|
f778fe |
- modifiers["force"],
|
|
|
f778fe |
- modifiers["wait"]
|
|
|
f778fe |
+ container_options=parts["container"],
|
|
|
f778fe |
+ network_options=parts["network"],
|
|
|
f778fe |
+ port_map_add=parts["port_map_add"],
|
|
|
f778fe |
+ port_map_remove=parts["port_map_remove"],
|
|
|
f778fe |
+ storage_map_add=parts["storage_map_add"],
|
|
|
f778fe |
+ storage_map_remove=parts["storage_map_remove"],
|
|
|
f778fe |
+ meta_attributes=parts["meta"],
|
|
|
f778fe |
+ force_options=modifiers["force"],
|
|
|
f778fe |
+ wait=modifiers["wait"]
|
|
|
f778fe |
)
|
|
|
f778fe |
diff --git a/pcs/test/cib_resource/test_bundle.py b/pcs/test/cib_resource/test_bundle.py
|
|
|
f778fe |
index d8c97c6..29e4339 100644
|
|
|
f778fe |
--- a/pcs/test/cib_resource/test_bundle.py
|
|
|
f778fe |
+++ b/pcs/test/cib_resource/test_bundle.py
|
|
|
f778fe |
@@ -75,6 +75,7 @@ class BundleCreate(BundleCreateCommon):
|
|
|
f778fe |
resource bundle create B1
|
|
|
f778fe |
container replicas=4 replicas-per-host=2 run-command=/bin/true
|
|
|
f778fe |
port-map port=1001
|
|
|
f778fe |
+ meta target-role=Stopped
|
|
|
f778fe |
network control-port=12345 host-interface=eth0 host-netmask=24
|
|
|
f778fe |
port-map id=B1-port-map-1001 internal-port=2002 port=2000
|
|
|
f778fe |
port-map range=3000-3300
|
|
|
f778fe |
@@ -83,6 +84,7 @@ class BundleCreate(BundleCreateCommon):
|
|
|
f778fe |
storage-map id=B1-storage-map source-dir=/tmp/docker2a
|
|
|
f778fe |
target-dir=/tmp/docker2b
|
|
|
f778fe |
container image=pcs:test masters=0
|
|
|
f778fe |
+ meta is-managed=false
|
|
|
f778fe |
storage-map source-dir-root=/tmp/docker3a
|
|
|
f778fe |
target-dir=/tmp/docker3b
|
|
|
f778fe |
storage-map id=B1-port-map-1001-1 source-dir-root=/tmp/docker4a
|
|
|
f778fe |
@@ -140,6 +142,18 @@ class BundleCreate(BundleCreateCommon):
|
|
|
f778fe |
target-dir="/tmp/docker4b"
|
|
|
f778fe |
/>
|
|
|
f778fe |
</storage>
|
|
|
f778fe |
+ <meta_attributes id="B1-meta_attributes">
|
|
|
f778fe |
+
|
|
|
f778fe |
+ id="B1-meta_attributes-is-managed"
|
|
|
f778fe |
+ name="is-managed"
|
|
|
f778fe |
+ value="false"
|
|
|
f778fe |
+ />
|
|
|
f778fe |
+
|
|
|
f778fe |
+ id="B1-meta_attributes-target-role"
|
|
|
f778fe |
+ name="target-role"
|
|
|
f778fe |
+ value="Stopped"
|
|
|
f778fe |
+ />
|
|
|
f778fe |
+ </meta_attributes>
|
|
|
f778fe |
</bundle>
|
|
|
f778fe |
</resources>
|
|
|
f778fe |
"""
|
|
|
f778fe |
@@ -215,6 +229,9 @@ class BundleCreate(BundleCreateCommon):
|
|
|
f778fe |
def test_empty_port_map(self):
|
|
|
f778fe |
self.assert_no_options("port-map")
|
|
|
f778fe |
|
|
|
f778fe |
+ def test_empty_meta(self):
|
|
|
f778fe |
+ self.assert_no_options("meta")
|
|
|
f778fe |
+
|
|
|
f778fe |
|
|
|
f778fe |
@skip_unless_pacemaker_supports_bundle
|
|
|
f778fe |
class BundleUpdate(BundleCreateCommon):
|
|
|
f778fe |
@@ -239,6 +256,7 @@ class BundleUpdate(BundleCreateCommon):
|
|
|
f778fe |
"storage-map source-dir=/tmp/docker1a target-dir=/tmp/docker1b "
|
|
|
f778fe |
"storage-map source-dir=/tmp/docker2a target-dir=/tmp/docker2b "
|
|
|
f778fe |
"storage-map source-dir=/tmp/docker3a target-dir=/tmp/docker3b "
|
|
|
f778fe |
+ "meta priority=15 resource-stickiness=100 is-managed=false "
|
|
|
f778fe |
).format(name)
|
|
|
f778fe |
)
|
|
|
f778fe |
|
|
|
f778fe |
@@ -282,6 +300,7 @@ class BundleUpdate(BundleCreateCommon):
|
|
|
f778fe |
port-map add internal-port=1003 port=2003
|
|
|
f778fe |
storage-map remove B-storage-map B-storage-map-2
|
|
|
f778fe |
storage-map add source-dir=/tmp/docker4a target-dir=/tmp/docker4b
|
|
|
f778fe |
+ meta priority=10 is-managed= target-role=Stopped
|
|
|
f778fe |
""",
|
|
|
f778fe |
"""
|
|
|
f778fe |
<resources>
|
|
|
f778fe |
@@ -319,6 +338,14 @@ class BundleUpdate(BundleCreateCommon):
|
|
|
f778fe |
target-dir="/tmp/docker4b"
|
|
|
f778fe |
/>
|
|
|
f778fe |
</storage>
|
|
|
f778fe |
+ <meta_attributes id="B-meta_attributes">
|
|
|
f778fe |
+
|
|
|
f778fe |
+ name="priority" value="10" />
|
|
|
f778fe |
+
|
|
|
f778fe |
+ name="resource-stickiness" value="100" />
|
|
|
f778fe |
+
|
|
|
f778fe |
+ name="target-role" value="Stopped" />
|
|
|
f778fe |
+ </meta_attributes>
|
|
|
f778fe |
</bundle>
|
|
|
f778fe |
</resources>
|
|
|
f778fe |
"""
|
|
|
f778fe |
@@ -373,6 +400,9 @@ class BundleUpdate(BundleCreateCommon):
|
|
|
f778fe |
def test_empty_port_map(self):
|
|
|
f778fe |
self.assert_no_options("port-map")
|
|
|
f778fe |
|
|
|
f778fe |
+ def test_empty_meta(self):
|
|
|
f778fe |
+ self.assert_no_options("meta")
|
|
|
f778fe |
+
|
|
|
f778fe |
|
|
|
f778fe |
@skip_unless_pacemaker_supports_bundle
|
|
|
f778fe |
class BundleShow(TestCase, AssertPcsMixin):
|
|
|
f778fe |
@@ -463,6 +493,35 @@ class BundleShow(TestCase, AssertPcsMixin):
|
|
|
f778fe |
"""
|
|
|
f778fe |
))
|
|
|
f778fe |
|
|
|
f778fe |
+ def test_meta(self):
|
|
|
f778fe |
+ self.assert_pcs_success(
|
|
|
f778fe |
+ "resource bundle create B1 container image=pcs:test --disabled"
|
|
|
f778fe |
+ )
|
|
|
f778fe |
+ self.assert_pcs_success("resource show B1", outdent(
|
|
|
f778fe |
+ # pylint:disable=trailing-whitespace
|
|
|
f778fe |
+ """\
|
|
|
f778fe |
+ Bundle: B1
|
|
|
f778fe |
+ Docker: image=pcs:test
|
|
|
f778fe |
+ Meta Attrs: target-role=Stopped
|
|
|
f778fe |
+ """
|
|
|
f778fe |
+ ))
|
|
|
f778fe |
+
|
|
|
f778fe |
+ def test_resource(self):
|
|
|
f778fe |
+ self.assert_pcs_success(
|
|
|
f778fe |
+ "resource bundle create B1 container image=pcs:test"
|
|
|
f778fe |
+ )
|
|
|
f778fe |
+ self.assert_pcs_success(
|
|
|
f778fe |
+ "resource create A ocf:pacemaker:Dummy bundle B1 --no-default-ops"
|
|
|
f778fe |
+ )
|
|
|
f778fe |
+ self.assert_pcs_success("resource show B1", outdent(
|
|
|
f778fe |
+ """\
|
|
|
f778fe |
+ Bundle: B1
|
|
|
f778fe |
+ Docker: image=pcs:test
|
|
|
f778fe |
+ Resource: A (class=ocf provider=pacemaker type=Dummy)
|
|
|
f778fe |
+ Operations: monitor interval=10 timeout=20 (A-monitor-interval-10)
|
|
|
f778fe |
+ """
|
|
|
f778fe |
+ ))
|
|
|
f778fe |
+
|
|
|
f778fe |
def test_all(self):
|
|
|
f778fe |
self.assert_pcs_success(
|
|
|
f778fe |
"""
|
|
|
f778fe |
@@ -474,9 +533,14 @@ class BundleShow(TestCase, AssertPcsMixin):
|
|
|
f778fe |
storage-map source-dir=/tmp/docker1a target-dir=/tmp/docker1b
|
|
|
f778fe |
storage-map id=my-storage-map source-dir=/tmp/docker2a
|
|
|
f778fe |
target-dir=/tmp/docker2b
|
|
|
f778fe |
+ meta target-role=Stopped is-managed=false
|
|
|
f778fe |
"""
|
|
|
f778fe |
)
|
|
|
f778fe |
+ self.assert_pcs_success(
|
|
|
f778fe |
+ "resource create A ocf:pacemaker:Dummy bundle B1 --no-default-ops"
|
|
|
f778fe |
+ )
|
|
|
f778fe |
self.assert_pcs_success("resource show B1", outdent(
|
|
|
f778fe |
+ # pylint:disable=trailing-whitespace
|
|
|
f778fe |
"""\
|
|
|
f778fe |
Bundle: B1
|
|
|
f778fe |
Docker: image=pcs:test masters=2 options="a b c" replicas=4
|
|
|
f778fe |
@@ -487,5 +551,8 @@ class BundleShow(TestCase, AssertPcsMixin):
|
|
|
f778fe |
Storage Mapping:
|
|
|
f778fe |
source-dir=/tmp/docker1a target-dir=/tmp/docker1b (B1-storage-map)
|
|
|
f778fe |
source-dir=/tmp/docker2a target-dir=/tmp/docker2b (my-storage-map)
|
|
|
f778fe |
+ Meta Attrs: is-managed=false target-role=Stopped
|
|
|
f778fe |
+ Resource: A (class=ocf provider=pacemaker type=Dummy)
|
|
|
f778fe |
+ Operations: monitor interval=10 timeout=20 (A-monitor-interval-10)
|
|
|
f778fe |
"""
|
|
|
f778fe |
))
|
|
|
f778fe |
diff --git a/pcs/test/cib_resource/test_manage_unmanage.py b/pcs/test/cib_resource/test_manage_unmanage.py
|
|
|
f778fe |
index 5b78646..2a87cd3 100644
|
|
|
f778fe |
--- a/pcs/test/cib_resource/test_manage_unmanage.py
|
|
|
f778fe |
+++ b/pcs/test/cib_resource/test_manage_unmanage.py
|
|
|
f778fe |
@@ -18,6 +18,7 @@ class ManageUnmanage(
|
|
|
f778fe |
TestCase,
|
|
|
f778fe |
get_assert_pcs_effect_mixin(
|
|
|
f778fe |
lambda cib: etree.tostring(
|
|
|
f778fe |
+ # pylint:disable=undefined-variable
|
|
|
f778fe |
etree.parse(cib).findall(".//resources")[0]
|
|
|
f778fe |
)
|
|
|
f778fe |
)
|
|
|
f778fe |
@@ -234,7 +235,7 @@ class ManageUnmanage(
|
|
|
f778fe |
|
|
|
f778fe |
self.assert_pcs_fail(
|
|
|
f778fe |
"resource unmanage A B",
|
|
|
f778fe |
- "Error: resource/clone/master/group 'B' does not exist\n"
|
|
|
f778fe |
+ "Error: resource/clone/master/group/bundle 'B' does not exist\n"
|
|
|
f778fe |
)
|
|
|
f778fe |
self.assert_resources_xml_in_cib(
|
|
|
f778fe |
"""
|
|
|
f778fe |
@@ -255,7 +256,7 @@ class ManageUnmanage(
|
|
|
f778fe |
|
|
|
f778fe |
self.assert_pcs_fail(
|
|
|
f778fe |
"resource manage A B",
|
|
|
f778fe |
- "Error: resource/clone/master/group 'B' does not exist\n"
|
|
|
f778fe |
+ "Error: resource/clone/master/group/bundle 'B' does not exist\n"
|
|
|
f778fe |
)
|
|
|
f778fe |
self.assert_resources_xml_in_cib(
|
|
|
f778fe |
"""
|
|
|
f778fe |
diff --git a/pcs/test/test_resource.py b/pcs/test/test_resource.py
|
|
|
f778fe |
index 96eae8f..4bdc194 100644
|
|
|
f778fe |
--- a/pcs/test/test_resource.py
|
|
|
f778fe |
+++ b/pcs/test/test_resource.py
|
|
|
f778fe |
@@ -8,6 +8,7 @@ from __future__ import (
|
|
|
f778fe |
from lxml import etree
|
|
|
f778fe |
import re
|
|
|
f778fe |
import shutil
|
|
|
f778fe |
+from textwrap import dedent
|
|
|
f778fe |
|
|
|
f778fe |
from pcs.test.tools import pcs_unittest as unittest
|
|
|
f778fe |
from pcs.test.tools.assertions import AssertPcsMixin
|
|
|
f778fe |
@@ -3321,11 +3322,11 @@ Error: Cannot remove more than one resource from cloned group
|
|
|
f778fe |
|
|
|
f778fe |
# bad resource name
|
|
|
f778fe |
o,r = pcs(temp_cib, "resource enable NoExist")
|
|
|
f778fe |
- ac(o,"Error: resource/clone/master/group 'NoExist' does not exist\n")
|
|
|
f778fe |
+ ac(o,"Error: resource/clone/master/group/bundle 'NoExist' does not exist\n")
|
|
|
f778fe |
assert r == 1
|
|
|
f778fe |
|
|
|
f778fe |
o,r = pcs(temp_cib, "resource disable NoExist")
|
|
|
f778fe |
- ac(o,"Error: resource/clone/master/group 'NoExist' does not exist\n")
|
|
|
f778fe |
+ ac(o,"Error: resource/clone/master/group/bundle 'NoExist' does not exist\n")
|
|
|
f778fe |
assert r == 1
|
|
|
f778fe |
|
|
|
f778fe |
# cloned group
|
|
|
f778fe |
@@ -3829,7 +3830,7 @@ Error: Cannot remove more than one resource from cloned group
|
|
|
f778fe |
|
|
|
f778fe |
self.assert_pcs_fail_regardless_of_force(
|
|
|
f778fe |
"resource enable dummy3 dummyX",
|
|
|
f778fe |
- "Error: resource/clone/master/group 'dummyX' does not exist\n"
|
|
|
f778fe |
+ "Error: resource/clone/master/group/bundle 'dummyX' does not exist\n"
|
|
|
f778fe |
)
|
|
|
f778fe |
self.assert_pcs_success(
|
|
|
f778fe |
"resource show --full",
|
|
|
f778fe |
@@ -3849,7 +3850,7 @@ Error: Cannot remove more than one resource from cloned group
|
|
|
f778fe |
|
|
|
f778fe |
self.assert_pcs_fail_regardless_of_force(
|
|
|
f778fe |
"resource disable dummy1 dummyX",
|
|
|
f778fe |
- "Error: resource/clone/master/group 'dummyX' does not exist\n"
|
|
|
f778fe |
+ "Error: resource/clone/master/group/bundle 'dummyX' does not exist\n"
|
|
|
f778fe |
)
|
|
|
f778fe |
self.assert_pcs_success(
|
|
|
f778fe |
"resource show --full",
|
|
|
f778fe |
@@ -4719,7 +4720,11 @@ class BundleCommon(
|
|
|
f778fe |
class BundleDeleteTest(BundleCommon):
|
|
|
f778fe |
def test_without_primitive(self):
|
|
|
f778fe |
self.fixture_bundle("B")
|
|
|
f778fe |
- self.assert_effect("resource delete B", "<resources/>")
|
|
|
f778fe |
+ self.assert_effect(
|
|
|
f778fe |
+ "resource delete B",
|
|
|
f778fe |
+ "<resources/>",
|
|
|
f778fe |
+ "Deleting bundle 'B'\n"
|
|
|
f778fe |
+ )
|
|
|
f778fe |
|
|
|
f778fe |
def test_with_primitive(self):
|
|
|
f778fe |
self.fixture_bundle("B")
|
|
|
f778fe |
@@ -4727,7 +4732,10 @@ class BundleDeleteTest(BundleCommon):
|
|
|
f778fe |
self.assert_effect(
|
|
|
f778fe |
"resource delete B",
|
|
|
f778fe |
"<resources/>",
|
|
|
f778fe |
- "Deleting Resource - R\n",
|
|
|
f778fe |
+ dedent("""\
|
|
|
f778fe |
+ Deleting bundle 'B' and its inner resource 'R'
|
|
|
f778fe |
+ Deleting Resource - R
|
|
|
f778fe |
+ """),
|
|
|
f778fe |
)
|
|
|
f778fe |
|
|
|
f778fe |
def test_remove_primitive(self):
|
|
|
f778fe |
@@ -4823,30 +4831,26 @@ class BundleCloneMaster(BundleCommon):
|
|
|
f778fe |
class BundleMiscCommands(BundleCommon):
|
|
|
f778fe |
def test_resource_enable_bundle(self):
|
|
|
f778fe |
self.fixture_bundle("B")
|
|
|
f778fe |
- self.assert_pcs_fail_regardless_of_force(
|
|
|
f778fe |
- "resource enable B",
|
|
|
f778fe |
- "Error: 'B' is not clone/master/a group/primitive\n"
|
|
|
f778fe |
+ self.assert_pcs_success(
|
|
|
f778fe |
+ "resource enable B"
|
|
|
f778fe |
)
|
|
|
f778fe |
|
|
|
f778fe |
def test_resource_disable_bundle(self):
|
|
|
f778fe |
self.fixture_bundle("B")
|
|
|
f778fe |
- self.assert_pcs_fail_regardless_of_force(
|
|
|
f778fe |
- "resource disable B",
|
|
|
f778fe |
- "Error: 'B' is not clone/master/a group/primitive\n"
|
|
|
f778fe |
+ self.assert_pcs_success(
|
|
|
f778fe |
+ "resource disable B"
|
|
|
f778fe |
)
|
|
|
f778fe |
|
|
|
f778fe |
def test_resource_manage_bundle(self):
|
|
|
f778fe |
self.fixture_bundle("B")
|
|
|
f778fe |
- self.assert_pcs_fail_regardless_of_force(
|
|
|
f778fe |
- "resource manage B",
|
|
|
f778fe |
- "Error: 'B' is not clone/master/a group/primitive\n"
|
|
|
f778fe |
+ self.assert_pcs_success(
|
|
|
f778fe |
+ "resource manage B"
|
|
|
f778fe |
)
|
|
|
f778fe |
|
|
|
f778fe |
def test_resource_unmanage_bundle(self):
|
|
|
f778fe |
self.fixture_bundle("B")
|
|
|
f778fe |
- self.assert_pcs_fail_regardless_of_force(
|
|
|
f778fe |
- "resource unmanage B",
|
|
|
f778fe |
- "Error: 'B' is not clone/master/a group/primitive\n"
|
|
|
f778fe |
+ self.assert_pcs_success(
|
|
|
f778fe |
+ "resource unmanage B"
|
|
|
f778fe |
)
|
|
|
f778fe |
|
|
|
f778fe |
def test_op_add(self):
|
|
|
f778fe |
diff --git a/pcs/usage.py b/pcs/usage.py
|
|
|
f778fe |
index d2262a6..75cb118 100644
|
|
|
f778fe |
--- a/pcs/usage.py
|
|
|
f778fe |
+++ b/pcs/usage.py
|
|
|
f778fe |
@@ -430,10 +430,12 @@ Commands:
|
|
|
f778fe |
|
|
|
f778fe |
bundle create <bundle id> [container [<container type>] <container options>]
|
|
|
f778fe |
[network <network options>] [port-map <port options>]...
|
|
|
f778fe |
- [storage-map <storage options>]... [--wait[=n]]
|
|
|
f778fe |
+ [storage-map <storage options>]... [meta <meta options>]
|
|
|
f778fe |
+ [--disabled] [--wait[=n]]
|
|
|
f778fe |
Create a new bundle encapsulating no resources. The bundle can be used
|
|
|
f778fe |
either as it is or a resource may be put into it at any time.
|
|
|
f778fe |
If the container type is not specified, it defaults to 'docker'.
|
|
|
f778fe |
+ If --disabled is specified, the bundle is not started automatically.
|
|
|
f778fe |
If --wait is specified, pcs will wait up to 'n' seconds for the bundle
|
|
|
f778fe |
to start and then return 0 on success or 1 on error. If 'n' is not
|
|
|
f778fe |
specified it defaults to 60 minutes.
|
|
|
f778fe |
@@ -442,13 +444,14 @@ Commands:
|
|
|
f778fe |
[network <network options>]
|
|
|
f778fe |
[port-map (add <port options>) | (remove <id>...)]...
|
|
|
f778fe |
[storage-map (add <storage options>) | (remove <id>...)]...
|
|
|
f778fe |
+ [meta <meta options>]
|
|
|
f778fe |
[--wait[=n]]
|
|
|
f778fe |
Add, remove or change options to specified bundle. If you wish to update
|
|
|
f778fe |
a resource encapsulated in the bundle, use the 'pcs resource update'
|
|
|
f778fe |
- command instead and specify the resource id. If --wait is specified,
|
|
|
f778fe |
+ command instead and specify the resource id. If --wait is specified,
|
|
|
f778fe |
pcs will wait up to 'n' seconds for the operation to finish (including
|
|
|
f778fe |
moving resources if appropriate) and then return 0 on success or 1 on
|
|
|
f778fe |
- error. If 'n' is not specified it defaults to 60 minutes.
|
|
|
f778fe |
+ error. If 'n' is not specified it defaults to 60 minutes.
|
|
|
f778fe |
|
|
|
f778fe |
manage <resource id>... [--monitor]
|
|
|
f778fe |
Set resources listed to managed mode (default). If --monitor is
|
|
|
f778fe |
--
|
|
|
f778fe |
1.8.3.1
|
|
|
f778fe |
|