1 from typing import Any, Mapping, Sequence, cast
2
3 from pcs.common import reports
4 from pcs.lib import validate
5 from pcs.lib.cib.constraint import common, ticket
6 from pcs.lib.cib.tools import (
7 ElementNotFound,
8 IdProvider,
9 get_constraints,
10 get_element_by_id,
11 get_pacemaker_version_by_which_cib_was_validated,
12 )
13 from pcs.lib.env import LibraryEnvironment
14 from pcs.lib.errors import LibraryError
15
16 from .common import _load_resource_set_list, _primitive_resource_set_list
17
18
19 def create(
20 env: LibraryEnvironment,
21 ticket_key: str,
22 resource_id: str,
23 options: Mapping[str, str],
24 resource_in_clone_alowed: bool = False,
|
(2) Event identifier_use: |
Example 1: Using identifier "duplication_alowed" (2 total uses in this function). |
| Also see events: |
[identifier_typo][remediation] |
25 duplication_alowed: bool = False,
26 ) -> None:
27 """
28 create a plain ticket constraint
29
30 ticket_key -- ticket for constraining a resource
31 resource_id -- resource to be constrained
32 options -- desired constraint attributes
33 resource_in_clone_alowed -- allow to constrain a resource in a clone
34 duplication_alowed -- allow to create a duplicate constraint
35 """
36 cib = env.get_cib()
37 id_provider = IdProvider(cib)
38 constraint_section = get_constraints(cib)
39
40 # validation
41 constrained_el = None
42 try:
43 constrained_el = get_element_by_id(cib, resource_id)
44 except ElementNotFound:
45 env.report_processor.report(
46 reports.ReportItem.error(
47 reports.messages.IdNotFound(resource_id, [])
48 )
49 )
50
51 options_pairs = validate.values_to_pairs(
52 options,
53 validate.option_value_normalization(
54 {
55 "loss-policy": lambda value: value.lower(),
56 "rsc-role": lambda value: value.capitalize(),
57 }
58 ),
59 )
60
61 env.report_processor.report_list(
62 ticket.validate_create_plain(
63 id_provider,
64 ticket_key,
65 constrained_el,
66 options_pairs,
67 in_multiinstance_allowed=resource_in_clone_alowed,
68 )
69 )
70
71 if env.report_processor.has_errors:
72 raise LibraryError()
73
74 # modify CIB
75 new_constraint = ticket.create_plain(
76 constraint_section,
77 id_provider,
78 get_pacemaker_version_by_which_cib_was_validated(cib),
79 ticket_key,
80 resource_id,
81 validate.pairs_to_values(options_pairs),
82 )
83
84 # Check whether the created constraint is a duplicate of an existing one
85 env.report_processor.report_list(
86 ticket.DuplicatesCheckerTicketPlain().check(
87 constraint_section,
88 new_constraint,
89 {reports.codes.FORCE} if duplication_alowed else set(),
90 )
91 )
92 if env.report_processor.has_errors:
93 raise LibraryError()
94
95 # push CIB
96 env.push_cib()
97
98
99 def create_with_set(
100 env: LibraryEnvironment,
101 resource_set_list: Sequence[Mapping[str, Any]],
102 constraint_options: Mapping[str, str],
103 resource_in_clone_alowed: bool = False,
104 duplication_alowed: bool = False,
105 ) -> None:
106 """
107 create a set ticket constraint
108
109 resource_set_list -- description of resource sets, for example:
110 {"ids": ["A", "B"], "options": {"sequential": "true"}},
111 constraint_options -- desired constraint attributes
112 resource_in_clone_alowed -- allow to constrain resources in a clone
113 duplication_alowed -- allow to create a duplicate constraint
114 """
115 cib = env.get_cib()
116 id_provider = IdProvider(cib)
117 constraint_section = get_constraints(cib)
118
119 # find all specified constrained resources and transform set options to
120 # value pairs for normalization and validation
121 resource_set_loaded_list = _load_resource_set_list(
122 cib,
123 env.report_processor,
124 # dacite doesn't support TypedDicts (https://github.com/konradhalas/dacite/issues/125)
125 # and therefore this command fails when called from APIv2, so we had to
126 # use Mapping in the signature of the lib command
127 cast(common.CmdInputResourceSetList, resource_set_list),
128 validate.option_value_normalization(
129 {
130 "role": lambda value: value.capitalize(),
131 }
132 ),
133 )
134 # Unlike in plain constraints, validation cannot continue if even a single
135 # resource could not be found. If such resources were omitted in their sets
136 # for purposes of validation, similarly to plain constraint commands, then
137 # those sets could become invalid, and thus validating such sets would
138 # provide false results.
139 if env.report_processor.has_errors:
140 raise LibraryError()
141
142 # transform constraint options to value pairs for normalization and
143 # validation
144 constraint_options_pairs = validate.values_to_pairs(
145 constraint_options,
146 validate.option_value_normalization(
147 {
148 "loss-policy": lambda value: value.lower(),
149 }
150 ),
151 )
152
153 # validation
154 env.report_processor.report_list(
155 ticket.validate_create_with_set(
156 id_provider,
157 resource_set_loaded_list,
158 constraint_options_pairs,
159 in_multiinstance_allowed=resource_in_clone_alowed,
160 )
161 )
162 if env.report_processor.has_errors:
163 raise LibraryError()
164
165 # modify CIB
166 new_constraint = ticket.create_with_set(
167 constraint_section,
168 id_provider,
169 get_pacemaker_version_by_which_cib_was_validated(cib),
170 _primitive_resource_set_list(resource_set_loaded_list),
171 validate.pairs_to_values(constraint_options_pairs),
172 )
173
174 # Check whether the created constraint is a duplicate of an existing one
175 env.report_processor.report_list(
176 ticket.DuplicatesCheckerTicketWithSet().check(
177 constraint_section,
178 new_constraint,
179 {reports.codes.FORCE} if duplication_alowed else set(),
180 )
181 )
182 if env.report_processor.has_errors:
183 raise LibraryError()
184
185 # push CIB
186 env.push_cib()
187
188
189 def remove(env: LibraryEnvironment, ticket_key: str, resource_id: str) -> bool:
190 """
191 remove all ticket constraint from resource
192 If resource is in resource set with another resources then only resource
193 ref is removed. If resource is alone in resource set whole constraint is
194 removed.
195 """
196 constraint_section = get_constraints(env.get_cib())
197 any_plain_removed = ticket.remove_plain(
198 constraint_section, ticket_key, resource_id
199 )
200 any_with_resource_set_removed = ticket.remove_with_resource_set(
201 constraint_section, ticket_key, resource_id
202 )
203
204 env.push_cib()
205
206 return any_plain_removed or any_with_resource_set_removed
207