1# Copyright (C) 2008-2011 Dejan Muhamedagic <dmuhamedagic@suse.de> 2# See COPYING for license information. 3 4from . import constants 5from . import clidisplay 6from . import utils 7from . import xmlutil 8 9 10# 11# CLI format generation utilities (from XML) 12# 13def cli_format(pl, break_lines=True, xml=False): 14 if break_lines and xml: 15 return ' \\\n'.join(pl) 16 elif break_lines: 17 return ' \\\n\t'.join(pl) 18 else: 19 return ' '.join(pl) 20 21 22def head_id_format(nodeid): 23 "Special format for property list / node id" 24 if utils.noquotes(nodeid): 25 return "%s:" % (clidisplay.ident(nodeid)) 26 return '%s="%s"' % (clidisplay.ident('$id'), 27 clidisplay.attr_value(nodeid)) 28 29 30def quote_wrap(v): 31 if utils.noquotes(v): 32 return v 33 elif '"' in v: 34 return '"%s"' % v.replace('"', '\\"') 35 else: 36 return '"%s"' % v 37 38 39def nvpair_format(n, v): 40 if v is None: 41 return clidisplay.attr_name(n) 42 else: 43 return '='.join((clidisplay.attr_name(n), 44 clidisplay.attr_value(quote_wrap(v)))) 45 46 47def cli_nvpair(nvp): 48 'Converts an nvpair tag or a (name, value) pair to CLI syntax' 49 from .cibconfig import cib_factory 50 from .utils import obscured 51 nodeid = nvp.get('id') 52 idref = nvp.get('id-ref') 53 name = nvp.get('name') 54 value = nvp.get('value') 55 value = obscured(name, value) 56 if idref is not None: 57 if name is not None: 58 return '@%s:%s' % (idref, name) 59 return '@%s' % (idref) 60 elif nodeid is not None and cib_factory.is_id_refd(nvp.tag, nodeid): 61 return '$%s:%s' % (nodeid, nvpair_format(name, value)) 62 return nvpair_format(name, value) 63 64 65def cli_nvpairs(nvplist): 66 'Return a string of name="value" pairs (passed in a list of nvpairs).' 67 return ' '.join([cli_nvpair(nvp) for nvp in nvplist]) 68 69 70def nvpairs2list(node, add_id=False): 71 ''' 72 Convert an attribute node to a list of nvpairs. 73 Also converts an id-ref or id into plain nvpairs. 74 The id attribute is normally skipped, since they tend to be 75 long and therefore obscure the relevant content. For some 76 elements, however, they are included (e.g. properties). 77 ''' 78 ret = [] 79 if 'id-ref' in node: 80 ret.append(xmlutil.nvpair('$id-ref', node.get('id-ref'))) 81 nvpairs = node.xpath('./nvpair | ./attributes/nvpair') 82 if 'id' in node and (add_id or len(nvpairs) == 0): 83 ret.append(xmlutil.nvpair('$id', node.get('id'))) 84 ret.extend(nvpairs) 85 return ret 86 87 88def date_exp2cli(node): 89 kwmap = {'in_range': 'in', 'date_spec': 'spec'} 90 l = [] 91 operation = node.get("operation") 92 l.append(clidisplay.keyword("date")) 93 l.append(clidisplay.keyword(kwmap.get(operation, operation))) 94 if operation in utils.olist(constants.simple_date_ops): 95 value = node.get(utils.keyword_cmp(operation, 'lt') and "end" or "start") 96 l.append(clidisplay.attr_value(quote_wrap(value))) 97 else: 98 if operation == 'in_range': 99 for name in constants.in_range_attrs: 100 if name in node.attrib: 101 l.append(nvpair_format(name, node.attrib[name])) 102 for c in node.iterchildren(): 103 if c.tag in ("duration", "date_spec"): 104 l.extend([nvpair_format(name, c.get(name)) 105 for name in list(c.keys()) if name != 'id']) 106 return ' '.join(l) 107 108 109def binary_op_format(op): 110 l = op.split(':') 111 if len(l) == 2: 112 return "%s:%s" % (l[0], clidisplay.keyword(l[1])) 113 else: 114 return clidisplay.keyword(op) 115 116 117def exp2cli(node): 118 operation = node.get("operation") 119 typ = node.get("type") 120 if typ: 121 operation = "%s:%s" % (typ, operation) 122 attribute = node.get("attribute") 123 value = node.get("value") 124 if not value: 125 return "%s %s" % (binary_op_format(operation), attribute) 126 else: 127 value_source = node.get("value-source") 128 if not value_source or value_source == "literal": 129 return "%s %s %s" % (attribute, binary_op_format(operation), value) 130 else: 131 return "%s %s %s{%s}" % (attribute, binary_op_format(operation), value_source, value) 132 133 134def abs_pos_score(score): 135 return score in ("inf", "+inf", "Mandatory") 136 137 138def get_kind(node): 139 kind = node.get("kind") 140 if not kind: 141 kind = "" 142 return kind 143 144 145def get_score(node): 146 score = node.get("score") 147 if not score: 148 score = node.get("score-attribute") 149 else: 150 if score.find("INFINITY") >= 0: 151 score = score.replace("INFINITY", "inf") 152 if not score: 153 score = "" 154 return score 155 156 157def cli_rule_score(node): 158 score = node.get("score") 159 if score == "INFINITY": 160 return None 161 return get_score(node) 162 163 164def cli_exprs(node): 165 bool_op = node.get("boolean-op") 166 if not bool_op: 167 bool_op = "and" 168 exp = [] 169 for c in node.iterchildren(): 170 if c.tag == "date_expression": 171 exp.append(date_exp2cli(c)) 172 elif c.tag == "expression": 173 exp.append(exp2cli(c)) 174 return (" %s " % clidisplay.keyword(bool_op)).join(exp) 175 176 177def cli_rule(node): 178 from .cibconfig import cib_factory 179 s = [] 180 node_id = node.get("id") 181 if node_id and cib_factory.is_id_refd(node.tag, node_id): 182 s.append(nvpair_format('$id', node_id)) 183 else: 184 idref = node.get("id-ref") 185 if idref: 186 return nvpair_format('$id-ref', idref) 187 rsc_role = node.get("role") 188 if rsc_role: 189 s.append(nvpair_format('$role', rsc_role)) 190 score = cli_rule_score(node) 191 if score: 192 s.append("%s:" % (clidisplay.score(score))) 193 s.append(cli_exprs(node)) 194 return ' '.join(s) 195 196 197def mkrscrole(node, n): 198 rsc = clidisplay.rscref(node.get(n)) 199 rsc_role = node.get(n + "-role") 200 rsc_instance = node.get(n + "-instance") 201 if rsc_role: 202 return "%s:%s" % (rsc, rsc_role) 203 elif rsc_instance: 204 return "%s:%s" % (rsc, rsc_instance) 205 else: 206 return rsc 207 208 209def mkrscaction(node, n): 210 rsc = clidisplay.rscref(node.get(n)) 211 rsc_action = node.get(n + "-action") 212 rsc_instance = node.get(n + "-instance") 213 if rsc_action: 214 return "%s:%s" % (rsc, rsc_action) 215 elif rsc_instance: 216 return "%s:%s" % (rsc, rsc_instance) 217 else: 218 return rsc 219 220 221def cli_path(p): 222 return clidisplay.attr_value(quote_wrap(p)) 223 224 225def boolean_maybe(v): 226 "returns True/False or None" 227 if v is None: 228 return None 229 return utils.get_boolean(v) 230 231 232def rsc_set_constraint(node, obj_type): 233 col = [] 234 cnt = 0 235 for n in node.findall("resource_set"): 236 sequential = boolean_maybe(n.get("sequential")) 237 require_all = boolean_maybe(n.get("require-all")) 238 if require_all is False: 239 col.append("[") 240 elif sequential is False: 241 col.append("(") 242 role = n.get("role") 243 action = n.get("action") 244 for r in n.findall("resource_ref"): 245 rsc = clidisplay.rscref(r.get("id")) 246 q = (obj_type == "order") and action or role 247 col.append(q and "%s:%s" % (rsc, q) or rsc) 248 cnt += 1 249 if require_all is False: 250 if sequential in (None, True): 251 col.append(nvpair_format('sequential', 'true')) 252 col.append("]") 253 elif sequential is False: 254 if require_all is False: 255 col.append(nvpair_format('require-all', 'false')) 256 col.append(")") 257 is_ticket = obj_type == 'rsc_ticket' 258 is_location = obj_type == 'location' 259 is_seq_all = sequential in (None, True) and require_all in (None, True) 260 if not is_location and ((is_seq_all and not is_ticket and cnt <= 2) or 261 (is_ticket and cnt <= 1)): # a degenerate thingie 262 col.insert(0, "_rsc_set_") 263 return col 264 265 266def simple_rsc_constraint(node, obj_type): 267 col = [] 268 if obj_type == "colocation": 269 col.append(mkrscrole(node, "rsc")) 270 col.append(mkrscrole(node, "with-rsc")) 271 elif obj_type == "order": 272 col.append(mkrscaction(node, "first")) 273 col.append(mkrscaction(node, "then")) 274 else: # rsc_ticket 275 col.append(mkrscrole(node, "rsc")) 276 return col 277 278 279# this pre (or post)-processing is oversimplified 280# but it will do for now 281# (a shortcut with more than one placeholder in a single expansion 282# cannot have more than one expansion) 283# ("...'@@'...'@@'...","...") <- that won't work 284def build_exp_re(exp_l): 285 return [x.replace(r'@@', r'([a-zA-Z_][a-zA-Z0-9_.-]*)') for x in exp_l] 286 287 288def match_acl_shortcut(xpath, re_l): 289 import re 290 for i in range(len(re_l)): 291 s = ''.join(re_l[0:i+1]) 292 r = re.match(s + r"$", xpath) 293 if r: 294 return (True, r.groups()[0:i+1]) 295 return (False, None) 296 297 298def find_acl_shortcut(xpath): 299 for shortcut in constants.acl_shortcuts: 300 l = build_exp_re(constants.acl_shortcuts[shortcut]) 301 (ec, spec_l) = match_acl_shortcut(xpath, l) 302 if ec: 303 return (shortcut, spec_l) 304 return (None, None) 305 306 307def acl_spec_format(xml_spec, v): 308 key_f = clidisplay.keyword(constants.acl_spec_map[xml_spec]) 309 if xml_spec == "xpath": 310 (shortcut, spec_l) = find_acl_shortcut(v) 311 if shortcut: 312 key_f = clidisplay.keyword(shortcut) 313 v_f = ':'.join([clidisplay.attr_value(x) for x in spec_l]) 314 else: 315 v_f = clidisplay.attr_value(quote_wrap(v)) 316 elif xml_spec == "ref": 317 v_f = '%s' % clidisplay.attr_value(v) 318 else: # tag and attribute 319 v_f = '%s' % clidisplay.attr_value(v) 320 return v_f and '%s:%s' % (key_f, v_f) or key_f 321 322 323def cli_acl_rule(node, format_mode=1): 324 l = [] 325 acl_rule_name = node.tag 326 l.append(clidisplay.keyword(acl_rule_name)) 327 for xml_spec in constants.acl_spec_map: 328 v = node.get(xml_spec) 329 if v: 330 l.append(acl_spec_format(xml_spec, v)) 331 return ' '.join(l) 332 333 334def cli_acl_roleref(node, format_mode=1): 335 return "%s:%s" % (clidisplay.keyword("role"), 336 clidisplay.attr_value(node.get("id"))) 337 338 339def cli_acl_role(node): 340 return clidisplay.attr_value(node.get("id")) 341 342 343def cli_acl_spec2_format(xml_spec, v): 344 key_f = clidisplay.keyword(xml_spec) 345 if xml_spec == "xpath": 346 (shortcut, spec_l) = find_acl_shortcut(v) 347 if shortcut: 348 key_f = clidisplay.keyword(shortcut) 349 v_f = ':'.join([clidisplay.attr_value(x) for x in spec_l]) 350 else: 351 v_f = clidisplay.attr_value(quote_wrap(v)) 352 else: # ref, type and attr 353 v_f = clidisplay.attr_value(v) 354 return v_f and '%s:%s' % (key_f, v_f) or key_f 355 356 357def cli_acl_permission(node): 358 s = [clidisplay.keyword(node.get('kind'))] 359 # if node.get('id'): 360 # s.append(head_id_format(node.get('id'))) 361 if node.get('description'): 362 s.append(nvpair_format('description', node.get('description'))) 363 for attrname, cliname in constants.acl_spec_map_2_rev: 364 if attrname in node.attrib: 365 s.append(cli_acl_spec2_format(cliname, node.get(attrname))) 366 return ' '.join(s) 367 368# 369################################################################ 370 371# vim:ts=4:sw=4:et: 372