File: puppet.py

package info (click to toggle)
pytest-testinfra 10.2.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 676 kB
  • sloc: python: 4,951; makefile: 152; sh: 2
file content (108 lines) | stat: -rw-r--r-- 2,961 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import json

from testinfra.modules.base import InstanceModule


def parse_puppet_resource(data: str) -> dict[str, dict[str, str]]:
    """Parse data returned by 'puppet resource'

    $ puppet resource user
    user { 'root':
        ensure  => 'present',
        comment => 'root',
        gid     => '0',
        home    => '/root',
        shell   => '/usr/bin/zsh',
        uid     => '0',
    }
    user { 'sshd':
      ensure => 'present',
      gid    => '65534',
      home   => '/var/run/sshd',
      shell  => '/usr/sbin/nologin',
      uid    => '106',
    }
    [...]
    """

    state: dict[str, dict[str, str]] = {}
    current = None
    for line in data.splitlines():
        if not current:
            current = line.split("'")[1]
            state[current] = {}
        elif current and line == "}":
            current = None
        elif current:
            key, value = line.split(" => ")
            key = key.strip()
            value = value.split("'")[1]
            state[current][key] = value
    return state


class PuppetResource(InstanceModule):
    """Get puppet resources

    Run ``puppet resource --types`` to get a list of available types.

    >>> host.puppet_resource("user", "www-data")
    {
        'www-data': {
            'ensure': 'present',
            'comment': 'www-data',
            'gid': '33',
            'home': '/var/www',
            'shell': '/usr/sbin/nologin',
            'uid': '33',
        },
    }
    """

    def __call__(self, resource_type, name=None):
        cmd = "puppet resource %s"
        args = [resource_type]
        if name is not None:
            cmd += " %s"
            args.append(name)
        # TODO(phil): Since puppet 4.0.0 puppet resource has a --to_yaml option
        return parse_puppet_resource(self.check_output(cmd, *args))

    def __repr__(self):
        return "<PuppetResource>"


class Facter(InstanceModule):
    """Get facts with `facter <https://puppetlabs.com/facter>`_

    >>> host.facter()
    {
        "operatingsystem": "Debian",
        "kernel": "linux",
        [...]
    }
    >>> host.facter("kernelversion", "is_virtual")
    {
      "kernelversion": "3.16.0",
      "is_virtual": "false"
    }
    """

    def __call__(self, *facts):
        cmd = "facter --json --puppet " + " ".join(facts)
        return json.loads(self.check_output(cmd))

    def __repr__(self):
        return "<facter>"