1""" 2:depends: kazoo 3:configuration: See :py:mod:`salt.modules.zookeeper` for setup instructions. 4 5ACLS 6~~~~ 7 8For more information about acls, please checkout the kazoo documentation. 9 10http://kazoo.readthedocs.io/en/latest/api/security.html#kazoo.security.make_digest_acl 11 12The following options can be included in the acl dictionary: 13 14 :param username: Username to use for the ACL. 15 :param password: A plain-text password to hash. 16 :param write: Write permission. 17 :type write: bool 18 :param create: Create permission. 19 :type create: bool 20 :param delete: Delete permission. 21 :type delete: bool 22 :param admin: Admin permission. 23 :type admin: bool 24 :param all: All permissions. 25 :type all: bool 26""" 27 28 29__virtualname__ = "zookeeper" 30 31 32def __virtual__(): 33 if "zookeeper.create" in __salt__: 34 return __virtualname__ 35 return (False, "zookeeper module could not be loaded") 36 37 38def _check_acls(left, right): 39 first = not bool(set(left) - set(right)) 40 second = not bool(set(right) - set(left)) 41 return first and second 42 43 44def present( 45 name, 46 value, 47 acls=None, 48 ephemeral=False, 49 sequence=False, 50 makepath=False, 51 version=-1, 52 profile=None, 53 hosts=None, 54 scheme=None, 55 username=None, 56 password=None, 57 default_acl=None, 58): 59 """ 60 Make sure znode is present in the correct state with the correct acls 61 62 name 63 path to znode 64 65 value 66 value znode should be set to 67 68 acls 69 list of acl dictionaries to set on znode (make sure the ones salt is connected with are included) 70 Default: None 71 72 ephemeral 73 Boolean to indicate if ephemeral znode should be created 74 Default: False 75 76 sequence 77 Boolean to indicate if znode path is suffixed with a unique index 78 Default: False 79 80 makepath 81 Boolean to indicate if the parent paths should be created 82 Default: False 83 84 version 85 For updating, specify the version which should be updated 86 Default: -1 (always match) 87 88 profile 89 Configured Zookeeper profile to authenticate with (Default: None) 90 91 hosts 92 Lists of Zookeeper Hosts (Default: '127.0.0.1:2181) 93 94 scheme 95 Scheme to authenticate with (Default: 'digest') 96 97 username 98 Username to authenticate (Default: None) 99 100 password 101 Password to authenticate (Default: None) 102 103 default_acl 104 Default acls to assign if a node is created in this connection (Default: None) 105 106 .. code-block:: yaml 107 108 add znode: 109 zookeeper.present: 110 - name: /test/name 111 - value: gtmanfred 112 - makepath: True 113 114 update znode: 115 zookeeper.present: 116 - name: /test/name 117 - value: daniel 118 - acls: 119 - username: daniel 120 password: test 121 read: true 122 - username: gtmanfred 123 password: test 124 read: true 125 write: true 126 create: true 127 delete: true 128 admin: true 129 - makepath: True 130 """ 131 132 ret = { 133 "name": name, 134 "result": False, 135 "comment": "Failed to setup znode {}".format(name), 136 "changes": {}, 137 } 138 connkwargs = { 139 "profile": profile, 140 "hosts": hosts, 141 "scheme": scheme, 142 "username": username, 143 "password": password, 144 "default_acl": default_acl, 145 } 146 if acls is None: 147 chk_acls = [] 148 else: 149 chk_acls = [__salt__["zookeeper.make_digest_acl"](**acl) for acl in acls] 150 if __salt__["zookeeper.exists"](name, **connkwargs): 151 cur_value = __salt__["zookeeper.get"](name, **connkwargs) 152 cur_acls = __salt__["zookeeper.get_acls"](name, **connkwargs) 153 if cur_value == value and _check_acls(cur_acls, chk_acls): 154 ret["result"] = True 155 ret[ 156 "comment" 157 ] = "Znode {} is already set to the correct value with the correct acls".format( 158 name 159 ) 160 return ret 161 elif __opts__["test"] is True: 162 ret["result"] = None 163 ret["comment"] = "Znode {} is will be updated".format(name) 164 ret["changes"]["old"] = {} 165 ret["changes"]["new"] = {} 166 if value != cur_value: 167 ret["changes"]["old"]["value"] = cur_value 168 ret["changes"]["new"]["value"] = value 169 if not _check_acls(chk_acls, cur_acls): 170 ret["changes"]["old"]["acls"] = cur_acls 171 ret["changes"]["new"]["acls"] = chk_acls 172 return ret 173 else: 174 value_result, acl_result = True, True 175 changes = {} 176 if value != cur_value: 177 __salt__["zookeeper.set"](name, value, version, **connkwargs) 178 new_value = __salt__["zookeeper.get"](name, **connkwargs) 179 value_result = new_value == value 180 changes.setdefault("new", {}).setdefault("value", new_value) 181 changes.setdefault("old", {}).setdefault("value", cur_value) 182 if chk_acls and not _check_acls(chk_acls, cur_acls): 183 __salt__["zookeeper.set_acls"](name, acls, version, **connkwargs) 184 new_acls = __salt__["zookeeper.get_acls"](name, **connkwargs) 185 acl_result = _check_acls(new_acls, chk_acls) 186 changes.setdefault("new", {}).setdefault("acls", new_acls) 187 changes.setdefault("old", {}).setdefault("value", cur_acls) 188 ret["changes"] = changes 189 if value_result and acl_result: 190 ret["result"] = True 191 ret["comment"] = "Znode {} successfully updated".format(name) 192 return ret 193 194 if __opts__["test"] is True: 195 ret["result"] = None 196 ret["comment"] = "{} is will be created".format(name) 197 ret["changes"]["old"] = {} 198 ret["changes"]["new"] = {} 199 ret["changes"]["new"]["acls"] = chk_acls 200 ret["changes"]["new"]["value"] = value 201 return ret 202 203 __salt__["zookeeper.create"]( 204 name, value, acls, ephemeral, sequence, makepath, **connkwargs 205 ) 206 207 value_result, acl_result = True, True 208 changes = {"old": {}} 209 210 new_value = __salt__["zookeeper.get"](name, **connkwargs) 211 value_result = new_value == value 212 changes.setdefault("new", {}).setdefault("value", new_value) 213 214 new_acls = __salt__["zookeeper.get_acls"](name, **connkwargs) 215 acl_result = acls is None or _check_acls(new_acls, chk_acls) 216 changes.setdefault("new", {}).setdefault("acls", new_acls) 217 218 ret["changes"] = changes 219 if value_result and acl_result: 220 ret["result"] = True 221 ret["comment"] = "Znode {} successfully created".format(name) 222 223 return ret 224 225 226def absent( 227 name, 228 version=-1, 229 recursive=False, 230 profile=None, 231 hosts=None, 232 scheme=None, 233 username=None, 234 password=None, 235 default_acl=None, 236): 237 """ 238 Make sure znode is absent 239 240 name 241 path to znode 242 243 version 244 Specify the version which should be deleted 245 Default: -1 (always match) 246 247 recursive 248 Boolean to indicate if children should be recursively deleted 249 Default: False 250 251 profile 252 Configured Zookeeper profile to authenticate with (Default: None) 253 254 hosts 255 Lists of Zookeeper Hosts (Default: '127.0.0.1:2181) 256 257 scheme 258 Scheme to authenticate with (Default: 'digest') 259 260 username 261 Username to authenticate (Default: None) 262 263 password 264 Password to authenticate (Default: None) 265 266 default_acl 267 Default acls to assign if a node is created in this connection (Default: None) 268 269 .. code-block:: yaml 270 271 delete znode: 272 zookeeper.absent: 273 - name: /test 274 - recursive: True 275 """ 276 ret = { 277 "name": name, 278 "result": False, 279 "comment": "Failed to delete znode {}".format(name), 280 "changes": {}, 281 } 282 connkwargs = { 283 "profile": profile, 284 "hosts": hosts, 285 "scheme": scheme, 286 "username": username, 287 "password": password, 288 "default_acl": default_acl, 289 } 290 291 if __salt__["zookeeper.exists"](name, **connkwargs) is False: 292 ret["result"] = True 293 ret["comment"] = "Znode {} does not exist".format(name) 294 return ret 295 296 changes = {} 297 changes["value"] = __salt__["zookeeper.get"](name, **connkwargs) 298 changes["acls"] = __salt__["zookeeper.get_acls"](name, **connkwargs) 299 if recursive is True: 300 changes["children"] = __salt__["zookeeper.get_children"](name, **connkwargs) 301 302 if __opts__["test"] is True: 303 ret["result"] = None 304 ret["comment"] = "Znode {} will be removed".format(name) 305 ret["changes"]["old"] = changes 306 return ret 307 308 __salt__["zookeeper.delete"](name, version, recursive, **connkwargs) 309 310 if __salt__["zookeeper.exists"](name, **connkwargs) is False: 311 ret["result"] = True 312 ret["comment"] = "Znode {} has been removed".format(name) 313 ret["changes"]["old"] = changes 314 315 return ret 316 317 318def acls( 319 name, 320 acls, 321 version=-1, 322 profile=None, 323 hosts=None, 324 scheme=None, 325 username=None, 326 password=None, 327 default_acl=None, 328): 329 """ 330 Update acls on a znode 331 332 name 333 path to znode 334 335 acls 336 list of acl dictionaries to set on znode 337 338 version 339 Specify the version which should be deleted 340 Default: -1 (always match) 341 342 profile 343 Configured Zookeeper profile to authenticate with (Default: None) 344 345 hosts 346 Lists of Zookeeper Hosts (Default: '127.0.0.1:2181) 347 348 scheme 349 Scheme to authenticate with (Default: 'digest') 350 351 username 352 Username to authenticate (Default: None) 353 354 password 355 Password to authenticate (Default: None) 356 357 default_acl 358 Default acls to assign if a node is created in this connection (Default: None) 359 360 .. code-block:: yaml 361 362 update acls: 363 zookeeper.acls: 364 - name: /test/name 365 - acls: 366 - username: daniel 367 password: test 368 all: True 369 - username: gtmanfred 370 password: test 371 all: True 372 """ 373 ret = { 374 "name": name, 375 "result": False, 376 "comment": "Failed to set acls on znode {}".format(name), 377 "changes": {}, 378 } 379 connkwargs = { 380 "profile": profile, 381 "hosts": hosts, 382 "scheme": scheme, 383 "username": username, 384 "password": password, 385 "default_acl": default_acl, 386 } 387 if isinstance(acls, dict): 388 acls = [acls] 389 chk_acls = [__salt__["zookeeper.make_digest_acl"](**acl) for acl in acls] 390 391 if not __salt__["zookeeper.exists"](name, **connkwargs): 392 ret["comment"] += ": Znode does not exist" 393 return ret 394 395 cur_acls = __salt__["zookeeper.get_acls"](name, **connkwargs) 396 if _check_acls(cur_acls, chk_acls): 397 ret["result"] = True 398 ret["comment"] = "Znode {} acls already set".format(name) 399 return ret 400 401 if __opts__["test"] is True: 402 ret["result"] = None 403 ret["comment"] = "Znode {} acls will be updated".format(name) 404 ret["changes"]["old"] = cur_acls 405 ret["changes"]["new"] = chk_acls 406 return ret 407 408 __salt__["zookeeper.set_acls"](name, acls, version, **connkwargs) 409 410 new_acls = __salt__["zookeeper.get_acls"](name, **connkwargs) 411 ret["changes"] = {"old": cur_acls, "new": new_acls} 412 if _check_acls(new_acls, chk_acls): 413 ret["result"] = True 414 ret["comment"] = "Znode {} acls updated".format(name) 415 return ret 416 ret["comment"] = "Znode {} acls failed to update".format(name) 417 return ret 418