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