1from __future__ import (absolute_import, division, print_function) 2import json 3from distutils.version import LooseVersion 4 5from ansible.module_utils._text import to_bytes, to_native 6 7from ansible_collections.containers.podman.plugins.module_utils.podman.common import lower_keys 8from ansible_collections.containers.podman.plugins.module_utils.podman.common import generate_systemd 9 10__metaclass__ = type 11 12ARGUMENTS_SPEC_POD = dict( 13 state=dict( 14 type='str', 15 default="created", 16 choices=[ 17 'created', 18 'killed', 19 'restarted', 20 'absent', 21 'started', 22 'stopped', 23 'paused', 24 'unpaused', 25 ]), 26 recreate=dict(type='bool', default=False), 27 add_host=dict(type='list', required=False, elements='str'), 28 cgroup_parent=dict(type='str', required=False), 29 dns=dict(type='list', elements='str', required=False), 30 dns_opt=dict(type='list', elements='str', required=False), 31 dns_search=dict(type='list', elements='str', required=False), 32 generate_systemd=dict(type='dict', default={}), 33 hostname=dict(type='str', required=False), 34 infra=dict(type='bool', required=False), 35 infra_conmon_pidfile=dict(type='str', required=False), 36 infra_command=dict(type='str', required=False), 37 infra_image=dict(type='str', required=False), 38 infra_name=dict(type='str', required=False), 39 ip=dict(type='str', required=False), 40 label=dict(type='dict', required=False), 41 label_file=dict(type='str', required=False), 42 mac_address=dict(type='str', required=False), 43 name=dict(type='str', required=True), 44 network=dict(type='str', required=False), 45 no_hosts=dict(type='bool', required=False), 46 pod_id_file=dict(type='str', required=False), 47 publish=dict(type='list', required=False, 48 elements='str', aliases=['ports']), 49 share=dict(type='str', required=False), 50 executable=dict(type='str', required=False, default='podman'), 51 debug=dict(type='bool', default=False), 52) 53 54 55class PodmanPodModuleParams: 56 """Creates list of arguments for podman CLI command. 57 58 Arguments: 59 action {str} -- action type from 'run', 'stop', 'create', 'delete', 60 'start' 61 params {dict} -- dictionary of module parameters 62 63 """ 64 65 def __init__(self, action, params, podman_version, module): 66 self.params = params 67 self.action = action 68 self.podman_version = podman_version 69 self.module = module 70 71 def construct_command_from_params(self): 72 """Create a podman command from given module parameters. 73 74 Returns: 75 list -- list of byte strings for Popen command 76 """ 77 if self.action in ['start', 'restart', 'stop', 'delete', 'pause', 78 'unpause', 'kill']: 79 return self._simple_action() 80 if self.action in ['create']: 81 return self._create_action() 82 self.module.fail_json(msg="Unknown action %s" % self.action) 83 84 def _simple_action(self): 85 if self.action in ['start', 'restart', 'stop', 'pause', 'unpause', 'kill']: 86 cmd = [self.action, self.params['name']] 87 return [to_bytes(i, errors='surrogate_or_strict') for i in cmd] 88 89 if self.action == 'delete': 90 cmd = ['rm', '-f', self.params['name']] 91 return [to_bytes(i, errors='surrogate_or_strict') for i in cmd] 92 self.module.fail_json(msg="Unknown action %s" % self.action) 93 94 def _create_action(self): 95 cmd = [self.action] 96 all_param_methods = [func for func in dir(self) 97 if callable(getattr(self, func)) 98 and func.startswith("addparam")] 99 params_set = (i for i in self.params if self.params[i] is not None) 100 for param in params_set: 101 func_name = "_".join(["addparam", param]) 102 if func_name in all_param_methods: 103 cmd = getattr(self, func_name)(cmd) 104 return [to_bytes(i, errors='surrogate_or_strict') for i in cmd] 105 106 def check_version(self, param, minv=None, maxv=None): 107 if minv and LooseVersion(minv) > LooseVersion( 108 self.podman_version): 109 self.module.fail_json(msg="Parameter %s is supported from podman " 110 "version %s only! Current version is %s" % ( 111 param, minv, self.podman_version)) 112 if maxv and LooseVersion(maxv) < LooseVersion( 113 self.podman_version): 114 self.module.fail_json(msg="Parameter %s is supported till podman " 115 "version %s only! Current version is %s" % ( 116 param, minv, self.podman_version)) 117 118 def addparam_add_host(self, c): 119 for g in self.params['add_host']: 120 c += ['--add-host', g] 121 return c 122 123 def addparam_cgroup_parent(self, c): 124 return c + ['--cgroup-parent', self.params['cgroup_parent']] 125 126 def addparam_dns(self, c): 127 for g in self.params['dns']: 128 c += ['--dns', g] 129 return c 130 131 def addparam_dns_opt(self, c): 132 for g in self.params['dns_opt']: 133 c += ['--dns-opt', g] 134 return c 135 136 def addparam_dns_search(self, c): 137 for g in self.params['dns_search']: 138 c += ['--dns-search', g] 139 return c 140 141 def addparam_hostname(self, c): 142 return c + ['--hostname', self.params['hostname']] 143 144 def addparam_infra(self, c): 145 return c + [b'='.join([b'--infra', 146 to_bytes(self.params['infra'], 147 errors='surrogate_or_strict')])] 148 149 def addparam_infra_conmon_pidfile(self, c): 150 return c + ['--infra-conmon-pidfile', self.params['infra_conmon_pidfile']] 151 152 def addparam_infra_command(self, c): 153 return c + ['--infra-command', self.params['infra_command']] 154 155 def addparam_infra_image(self, c): 156 return c + ['--infra-image', self.params['infra_image']] 157 158 def addparam_infra_name(self, c): 159 return c + ['--infra-name', self.params['infra_name']] 160 161 def addparam_ip(self, c): 162 return c + ['--ip', self.params['ip']] 163 164 def addparam_label(self, c): 165 for label in self.params['label'].items(): 166 c += ['--label', b'='.join( 167 [to_bytes(i, errors='surrogate_or_strict') for i in label])] 168 return c 169 170 def addparam_label_file(self, c): 171 return c + ['--label-file', self.params['label_file']] 172 173 def addparam_mac_address(self, c): 174 return c + ['--mac-address', self.params['mac_address']] 175 176 def addparam_name(self, c): 177 return c + ['--name', self.params['name']] 178 179 def addparam_network(self, c): 180 return c + ['--network', self.params['network']] 181 182 def addparam_no_hosts(self, c): 183 return c + ["=".join('--no-hosts', self.params['no_hosts'])] 184 185 def addparam_pod_id_file(self, c): 186 return c + ['--pod-id-file', self.params['pod_id_file']] 187 188 def addparam_publish(self, c): 189 for g in self.params['publish']: 190 c += ['--publish', g] 191 return c 192 193 def addparam_share(self, c): 194 return c + ['--share', self.params['share']] 195 196 197class PodmanPodDefaults: 198 def __init__(self, module, podman_version): 199 self.module = module 200 self.version = podman_version 201 self.defaults = { 202 'add_host': [], 203 'dns': [], 204 'dns_opt': [], 205 'dns_search': [], 206 'infra': True, 207 'label': {}, 208 } 209 210 def default_dict(self): 211 # make here any changes to self.defaults related to podman version 212 # https://github.com/containers/libpod/pull/5669 213 # if (LooseVersion(self.version) >= LooseVersion('1.8.0') 214 # and LooseVersion(self.version) < LooseVersion('1.9.0')): 215 # self.defaults['cpu_shares'] = 1024 216 return self.defaults 217 218 219class PodmanPodDiff: 220 def __init__(self, module, module_params, info, infra_info, podman_version): 221 self.module = module 222 self.module_params = module_params 223 self.version = podman_version 224 self.default_dict = None 225 self.info = lower_keys(info) 226 self.infra_info = lower_keys(infra_info) 227 self.params = self.defaultize() 228 self.diff = {'before': {}, 'after': {}} 229 self.non_idempotent = {} 230 231 def defaultize(self): 232 params_with_defaults = {} 233 self.default_dict = PodmanPodDefaults( 234 self.module, self.version).default_dict() 235 for p in self.module_params: 236 if self.module_params[p] is None and p in self.default_dict: 237 params_with_defaults[p] = self.default_dict[p] 238 else: 239 params_with_defaults[p] = self.module_params[p] 240 return params_with_defaults 241 242 def _diff_update_and_compare(self, param_name, before, after): 243 if before != after: 244 self.diff['before'].update({param_name: before}) 245 self.diff['after'].update({param_name: after}) 246 return True 247 return False 248 249 def diffparam_add_host(self): 250 if not self.infra_info: 251 return self._diff_update_and_compare('add_host', '', '') 252 before = self.infra_info['hostconfig']['extrahosts'] or [] 253 after = self.params['add_host'] 254 before, after = sorted(list(set(before))), sorted(list(set(after))) 255 return self._diff_update_and_compare('add_host', before, after) 256 257 def diffparam_cgroup_parent(self): 258 if 'cgroupparent' in self.info: 259 before = self.info['cgroupparent'] 260 elif 'config' in self.info and self.info['config'].get('cgroupparent'): 261 before = self.info['config']['cgroupparent'] 262 after = self.params['cgroup_parent'] or before 263 return self._diff_update_and_compare('cgroup_parent', before, after) 264 265 def diffparam_dns(self): 266 if not self.infra_info: 267 return self._diff_update_and_compare('dns', '', '') 268 before = self.infra_info['hostconfig']['dns'] or [] 269 after = self.params['dns'] 270 before, after = sorted(list(set(before))), sorted(list(set(after))) 271 return self._diff_update_and_compare('dns', before, after) 272 273 def diffparam_dns_opt(self): 274 if not self.infra_info: 275 return self._diff_update_and_compare('dns_opt', '', '') 276 before = self.infra_info['hostconfig']['dnsoptions'] or [] 277 after = self.params['dns_opt'] 278 before, after = sorted(list(set(before))), sorted(list(set(after))) 279 return self._diff_update_and_compare('dns_opt', before, after) 280 281 def diffparam_dns_search(self): 282 if not self.infra_info: 283 return self._diff_update_and_compare('dns_search', '', '') 284 before = self.infra_info['hostconfig']['dnssearch'] or [] 285 after = self.params['dns_search'] 286 before, after = sorted(list(set(before))), sorted(list(set(after))) 287 return self._diff_update_and_compare('dns_search', before, after) 288 289 def diffparam_hostname(self): 290 if not self.infra_info: 291 return self._diff_update_and_compare('hostname', '', '') 292 before = self.infra_info['config']['hostname'] 293 after = self.params['hostname'] or before 294 return self._diff_update_and_compare('hostname', before, after) 295 296 # TODO(sshnaidm): https://github.com/containers/podman/issues/6968 297 def diffparam_infra(self): 298 if 'state' in self.info and 'infracontainerid' in self.info['state']: 299 before = self.info['state']['infracontainerid'] != "" 300 else: 301 # TODO(sshnaidm): https://github.com/containers/podman/issues/6968 302 before = 'infracontainerid' in self.info 303 after = self.params['infra'] 304 return self._diff_update_and_compare('infra', before, after) 305 306 # TODO(sshnaidm): https://github.com/containers/podman/issues/6969 307 # def diffparam_infra_command(self): 308 # before = str(self.info['hostconfig']['infra_command']) 309 # after = self.params['infra_command'] 310 # return self._diff_update_and_compare('infra_command', before, after) 311 312 def diffparam_infra_image(self): 313 if not self.infra_info: 314 return self._diff_update_and_compare('infra_image', '', '') 315 before = str(self.infra_info['imagename']) 316 after = before 317 if self.module_params['infra_image']: 318 after = self.params['infra_image'] 319 before = before.replace(":latest", "") 320 after = after.replace(":latest", "") 321 before = before.split("/")[-1] # pylint: disable=W,C,R 322 after = after.split("/")[-1] # pylint: disable=W,C,R 323 return self._diff_update_and_compare('infra_image', before, after) 324 325 # TODO(sshnaidm): https://github.com/containers/podman/pull/6956 326 # def diffparam_ip(self): 327 # before = str(self.info['hostconfig']['ip']) 328 # after = self.params['ip'] 329 # return self._diff_update_and_compare('ip', before, after) 330 331 def diffparam_label(self): 332 if 'config' in self.info and 'labels' in self.info['config']: 333 before = self.info['config'].get('labels') or {} 334 else: 335 before = self.info['labels'] if 'labels' in self.info else {} 336 after = self.params['label'] 337 return self._diff_update_and_compare('label', before, after) 338 339 # TODO(sshnaidm): https://github.com/containers/podman/pull/6956 340 # def diffparam_mac_address(self): 341 # before = str(self.info['hostconfig']['mac_address']) 342 # after = self.params['mac_address'] 343 # return self._diff_update_and_compare('mac_address', before, after) 344 345 def diffparam_network(self): 346 if not self.infra_info: 347 return self._diff_update_and_compare('network', [], []) 348 net_mode_before = self.infra_info['hostconfig']['networkmode'] 349 net_mode_after = '' 350 before = list(self.infra_info['networksettings'].get('networks', {})) 351 # Remove default 'podman' network in v3 for comparison 352 if before == ['podman']: 353 before = [] 354 after = self.params['network'] 355 # Currently supported only 'host' and 'none' network modes idempotency 356 if after in ['bridge', 'host', 'slirp4netns']: 357 net_mode_after = after 358 elif after: 359 after = after.split(",") 360 else: 361 after = [] 362 if net_mode_after and not before: 363 # Remove differences between v1 and v2 364 net_mode_after = net_mode_after.replace('bridge', 'default') 365 net_mode_after = net_mode_after.replace('slirp4netns', 'default') 366 net_mode_before = net_mode_before.replace('bridge', 'default') 367 net_mode_before = net_mode_before.replace('slirp4netns', 'default') 368 return self._diff_update_and_compare('network', net_mode_before, net_mode_after) 369 before, after = sorted(list(set(before))), sorted(list(set(after))) 370 return self._diff_update_and_compare('network', before, after) 371 372 # TODO(sshnaidm) 373 # def diffparam_no_hosts(self): 374 # before = str(self.info['hostconfig']['no_hosts']) 375 # after = self.params['no_hosts'] 376 # return self._diff_update_and_compare('no_hosts', before, after) 377 378 # TODO(sshnaidm) Need to add port ranges support 379 def diffparam_publish(self): 380 if not self.infra_info: 381 return self._diff_update_and_compare('publish', '', '') 382 ports = self.infra_info['hostconfig']['portbindings'] 383 before = [":".join([ 384 j[0]['hostip'], 385 str(j[0]["hostport"]), 386 i.replace('/tcp', '') 387 ]).strip(':') for i, j in ports.items()] 388 after = self.params['publish'] or [] 389 after = [ 390 i.replace("/tcp", "").replace("[", "").replace("]", "").strip(":") 391 for i in after] 392 # No support for port ranges yet 393 for ports in after: 394 if "-" in ports: 395 return self._diff_update_and_compare('publish', '', '') 396 before, after = sorted(list(set(before))), sorted(list(set(after))) 397 return self._diff_update_and_compare('publish', before, after) 398 399 def diffparam_share(self): 400 if not self.infra_info: 401 return self._diff_update_and_compare('share', '', '') 402 if 'sharednamespaces' in self.info: 403 before = self.info['sharednamespaces'] 404 elif 'config' in self.info: 405 before = [ 406 i.split('shares')[1].lower() 407 for i in self.info['config'] if 'shares' in i] 408 # TODO(sshnaidm): to discover why in podman v1 'cgroup' appears 409 before.remove('cgroup') 410 else: 411 before = [] 412 if self.params['share'] is not None: 413 after = self.params['share'].split(",") 414 else: 415 after = ['uts', 'ipc', 'net'] 416 before, after = sorted(list(set(before))), sorted(list(set(after))) 417 return self._diff_update_and_compare('share', before, after) 418 419 def is_different(self): 420 diff_func_list = [func for func in dir(self) 421 if callable(getattr(self, func)) and func.startswith( 422 "diffparam")] 423 fail_fast = not bool(self.module._diff) 424 different = False 425 for func_name in diff_func_list: 426 dff_func = getattr(self, func_name) 427 if dff_func(): 428 if fail_fast: 429 return True 430 different = True 431 # Check non idempotent parameters 432 for p in self.non_idempotent: 433 if self.module_params[p] is not None and self.module_params[p] not in [{}, [], '']: 434 different = True 435 return different 436 437 438class PodmanPod: 439 """Perform pod tasks. 440 441 Manages podman pod, inspects it and checks its current state 442 """ 443 444 def __init__(self, module, name, module_params): 445 """Initialize PodmanPod class. 446 447 Arguments: 448 module {obj} -- ansible module object 449 name {str} -- name of pod 450 """ 451 452 self.module = module 453 self.module_params = module_params 454 self.name = name 455 self.stdout, self.stderr = '', '' 456 self.info = self.get_info() 457 self.infra_info = self.get_infra_info() 458 self.version = self._get_podman_version() 459 self.diff = {} 460 self.actions = [] 461 462 @property 463 def exists(self): 464 """Check if pod exists.""" 465 return bool(self.info != {}) 466 467 @property 468 def different(self): 469 """Check if pod is different.""" 470 diffcheck = PodmanPodDiff( 471 self.module, 472 self.module_params, 473 self.info, 474 self.infra_info, 475 self.version) 476 is_different = diffcheck.is_different() 477 diffs = diffcheck.diff 478 if self.module._diff and is_different and diffs['before'] and diffs['after']: 479 self.diff['before'] = "\n".join( 480 ["%s - %s" % (k, v) for k, v in sorted( 481 diffs['before'].items())]) + "\n" 482 self.diff['after'] = "\n".join( 483 ["%s - %s" % (k, v) for k, v in sorted( 484 diffs['after'].items())]) + "\n" 485 return is_different 486 487 @property 488 def running(self): 489 """Return True if pod is running now.""" 490 if 'status' in self.info['State']: 491 return self.info['State']['status'] == 'Running' 492 return self.info['State'] == 'Running' 493 494 @property 495 def paused(self): 496 """Return True if pod is paused now.""" 497 if 'status' in self.info['State']: 498 return self.info['State']['status'] == 'Paused' 499 return self.info['State'] == 'Paused' 500 501 @property 502 def stopped(self): 503 """Return True if pod exists and is not running now.""" 504 if not self.exists: 505 return False 506 if 'status' in self.info['State']: 507 return not (self.info['State']['status'] == 'Running') 508 return not (self.info['State'] == 'Running') 509 510 def get_info(self): 511 """Inspect pod and gather info about it.""" 512 # pylint: disable=unused-variable 513 rc, out, err = self.module.run_command( 514 [self.module_params['executable'], b'pod', b'inspect', self.name]) 515 return json.loads(out) if rc == 0 else {} 516 517 def get_infra_info(self): 518 """Inspect pod and gather info about it.""" 519 if not self.info: 520 return {} 521 if 'InfraContainerID' in self.info: 522 infra_container_id = self.info['InfraContainerID'] 523 elif 'State' in self.info and 'infraContainerID' in self.info['State']: 524 infra_container_id = self.info['State']['infraContainerID'] 525 else: 526 return {} 527 # pylint: disable=unused-variable 528 rc, out, err = self.module.run_command( 529 [self.module_params['executable'], b'inspect', infra_container_id]) 530 return json.loads(out)[0] if rc == 0 else {} 531 532 def _get_podman_version(self): 533 # pylint: disable=unused-variable 534 rc, out, err = self.module.run_command( 535 [self.module_params['executable'], b'--version']) 536 if rc != 0 or not out or "version" not in out: 537 self.module.fail_json(msg="%s run failed!" % self.module_params['executable']) 538 return out.split("version")[1].strip() 539 540 def _perform_action(self, action): 541 """Perform action with pod. 542 543 Arguments: 544 action {str} -- action to perform - start, create, stop, pause 545 unpause, delete, restart, kill 546 """ 547 b_command = PodmanPodModuleParams(action, 548 self.module_params, 549 self.version, 550 self.module, 551 ).construct_command_from_params() 552 full_cmd = " ".join([self.module_params['executable'], 'pod'] 553 + [to_native(i) for i in b_command]) 554 self.module.log("PODMAN-POD-DEBUG: %s" % full_cmd) 555 self.actions.append(full_cmd) 556 if not self.module.check_mode: 557 rc, out, err = self.module.run_command( 558 [self.module_params['executable'], b'pod'] + b_command, 559 expand_user_and_vars=False) 560 self.stdout = out 561 self.stderr = err 562 if rc != 0: 563 self.module.fail_json( 564 msg="Can't %s pod %s" % (action, self.name), 565 stdout=out, stderr=err) 566 567 def delete(self): 568 """Delete the pod.""" 569 self._perform_action('delete') 570 571 def stop(self): 572 """Stop the pod.""" 573 self._perform_action('stop') 574 575 def start(self): 576 """Start the pod.""" 577 self._perform_action('start') 578 579 def create(self): 580 """Create the pod.""" 581 self._perform_action('create') 582 583 def recreate(self): 584 """Recreate the pod.""" 585 self.delete() 586 self.create() 587 588 def restart(self): 589 """Restart the pod.""" 590 self._perform_action('restart') 591 592 def kill(self): 593 """Kill the pod.""" 594 self._perform_action('kill') 595 596 def pause(self): 597 """Pause the pod.""" 598 self._perform_action('pause') 599 600 def unpause(self): 601 """Unpause the pod.""" 602 self._perform_action('unpause') 603 604 605class PodmanPodManager: 606 """Module manager class. 607 608 Defines according to parameters what actions should be applied to pod 609 """ 610 611 def __init__(self, module, params): 612 """Initialize PodmanManager class. 613 614 Arguments: 615 module {obj} -- ansible module object 616 """ 617 618 self.module = module 619 self.module_params = params 620 self.results = { 621 'changed': False, 622 'actions': [], 623 'pod': {}, 624 } 625 self.name = self.module_params['name'] 626 self.executable = \ 627 self.module.get_bin_path(self.module_params['executable'], 628 required=True) 629 self.state = self.module_params['state'] 630 self.recreate = self.module_params['recreate'] 631 self.pod = PodmanPod(self.module, self.name, self.module_params) 632 633 def update_pod_result(self, changed=True): 634 """Inspect the current pod, update results with last info, exit. 635 636 Keyword Arguments: 637 changed {bool} -- whether any action was performed 638 (default: {True}) 639 """ 640 facts = self.pod.get_info() if changed else self.pod.info 641 out, err = self.pod.stdout, self.pod.stderr 642 self.results.update({'changed': changed, 'pod': facts, 643 'podman_actions': self.pod.actions}, 644 stdout=out, stderr=err) 645 if self.pod.diff: 646 self.results.update({'diff': self.pod.diff}) 647 if self.module.params['debug'] or self.module_params['debug']: 648 self.results.update({'podman_version': self.pod.version}) 649 self.results.update( 650 {'podman_systemd': generate_systemd(self.module, self.module_params, self.name)}) 651 652 def execute(self): 653 """Execute the desired action according to map of actions & states.""" 654 states_map = { 655 'created': self.make_created, 656 'started': self.make_started, 657 'stopped': self.make_stopped, 658 'restarted': self.make_restarted, 659 'absent': self.make_absent, 660 'killed': self.make_killed, 661 'paused': self.make_paused, 662 'unpaused': self.make_unpaused, 663 664 } 665 process_action = states_map[self.state] 666 process_action() 667 return self.results 668 669 def _create_or_recreate_pod(self): 670 """Ensure pod exists and is exactly as it should be by input params.""" 671 changed = False 672 if self.pod.exists: 673 if self.pod.different or self.recreate: 674 self.pod.recreate() 675 self.results['actions'].append('recreated %s' % self.pod.name) 676 changed = True 677 elif not self.pod.exists: 678 self.pod.create() 679 self.results['actions'].append('created %s' % self.pod.name) 680 changed = True 681 return changed 682 683 def make_created(self): 684 """Run actions if desired state is 'created'.""" 685 if self.pod.exists and not self.pod.different: 686 self.update_pod_result(changed=False) 687 return 688 self._create_or_recreate_pod() 689 self.update_pod_result() 690 691 def make_killed(self): 692 """Run actions if desired state is 'killed'.""" 693 self._create_or_recreate_pod() 694 self.pod.kill() 695 self.results['actions'].append('killed %s' % self.pod.name) 696 self.update_pod_result() 697 698 def make_paused(self): 699 """Run actions if desired state is 'paused'.""" 700 changed = self._create_or_recreate_pod() 701 if self.pod.paused: 702 self.update_pod_result(changed=changed) 703 return 704 self.pod.pause() 705 self.results['actions'].append('paused %s' % self.pod.name) 706 self.update_pod_result() 707 708 def make_unpaused(self): 709 """Run actions if desired state is 'unpaused'.""" 710 changed = self._create_or_recreate_pod() 711 if not self.pod.paused: 712 self.update_pod_result(changed=changed) 713 return 714 self.pod.unpause() 715 self.results['actions'].append('unpaused %s' % self.pod.name) 716 self.update_pod_result() 717 718 def make_started(self): 719 """Run actions if desired state is 'started'.""" 720 changed = self._create_or_recreate_pod() 721 if not changed and self.pod.running: 722 self.update_pod_result(changed=changed) 723 return 724 725 # self.pod.unpause() TODO(sshnaidm): to unpause if state == started? 726 self.pod.start() 727 self.results['actions'].append('started %s' % self.pod.name) 728 self.update_pod_result() 729 730 def make_stopped(self): 731 """Run actions if desired state is 'stopped'.""" 732 if not self.pod.exists: 733 self.module.fail_json("Pod %s doesn't exist!" % self.pod.name) 734 if self.pod.running: 735 self.pod.stop() 736 self.results['actions'].append('stopped %s' % self.pod.name) 737 self.update_pod_result() 738 elif self.pod.stopped: 739 self.update_pod_result(changed=False) 740 741 def make_restarted(self): 742 """Run actions if desired state is 'restarted'.""" 743 if self.pod.exists: 744 self.pod.restart() 745 self.results['actions'].append('restarted %s' % self.pod.name) 746 self.results.update({'changed': True}) 747 self.update_pod_result() 748 else: 749 self.module.fail_json("Pod %s doesn't exist!" % self.pod.name) 750 751 def make_absent(self): 752 """Run actions if desired state is 'absent'.""" 753 if not self.pod.exists: 754 self.results.update({'changed': False}) 755 elif self.pod.exists: 756 self.pod.delete() 757 self.results['actions'].append('deleted %s' % self.pod.name) 758 self.results.update({'changed': True}) 759 self.results.update({'pod': {}, 760 'podman_actions': self.pod.actions}) 761