├── .flake8
├── .fmf
└── version
├── .github
├── dependabot.yml
├── pull_request_template.md
└── workflows
│ ├── codespell.yml
│ ├── docstring_validation.yml
│ ├── pytest.yml
│ ├── stylish.yml
│ └── testimony.yml
├── .gitleaks.toml
├── .packit.yaml
├── .sourcery.yaml
├── .testing-farm.yaml
├── LICENSE
├── README.md
├── TESTING.md
├── data
├── .exp.sed
├── cert-api.access.redhat.com.pem
├── insights-client.conf
├── insights-client.motd
├── logrotate.d
│ ├── insights-client
│ └── meson.build
├── meson.build
├── redhattools.pub.gpg
├── rpm.egg
├── rpm.egg.asc
├── systemd
│ ├── 80-insights-register.preset
│ ├── 80-insights.preset
│ ├── insights-client-boot.service
│ ├── insights-client-checkin.service.in
│ ├── insights-client-checkin.timer
│ ├── insights-client-results.path.in
│ ├── insights-client-results.service.in
│ ├── insights-client.service
│ ├── insights-client.timer
│ ├── insights-register.path.in
│ ├── insights-register.service.in
│ ├── insights-unregister.path.in
│ ├── insights-unregister.service.in
│ └── meson.build
└── tmpfiles.d
│ ├── insights-client.conf
│ └── meson.build
├── docs
├── file-content-redaction.yaml.example
├── file-redaction.yaml.example
├── insights-client.8
├── insights-client.conf.5
└── meson.build
├── insights-client.spec
├── integration-tests
├── README.md
├── __init__.py
├── conftest.py
├── constants.py
├── custom_betelgeuse_config.py
├── playbook_verifier
│ ├── __init__.py
│ ├── playbooks
│ │ ├── README.md
│ │ ├── bugs.yml
│ │ ├── compliance_openscap_setup.yml
│ │ └── insights_setup.yml
│ └── test_verifier.py
├── requirements.txt
├── test_checkin.py
├── test_client.py
├── test_client_options.py
├── test_client_systemd.py
├── test_collection.py
├── test_common_specs.py
├── test_compliance.py
├── test_connection.py
├── test_display_name_option.py
├── test_e2e.py
├── test_file_workflow.py
├── test_manpage.py
├── test_motd.py
├── test_obfuscation.py
├── test_redaction.py
├── test_registration.py
├── test_status.py
├── test_tags.py
├── test_unregister.py
├── test_upload.py
├── test_version.py
└── testimony.yml
├── meson.build
├── meson_options.txt
├── pyproject.toml
├── pytest.ini
├── requirements-dev.txt
├── scripts
├── 01-upgrade-egg.sh
└── README.md
├── src
├── insights-client.in
├── insights_client
│ ├── __init__.py
│ ├── constants.py.in
│ ├── meson.build
│ ├── run.py
│ ├── tests
│ │ ├── conftest.py
│ │ ├── meson.build
│ │ ├── requirements-core.txt
│ │ ├── requirements.txt
│ │ ├── test_client.py
│ │ ├── test_commands.py
│ │ ├── test_motd.py
│ │ └── test_sed.py
│ └── utc.py
├── meson.build
└── redhat-access-insights.in
└── systemtest
├── copr-setup.sh
├── guest-setup.sh
├── insights-core-setup.sh
├── plans
└── main.fmf
└── tests
└── integration
├── main.fmf
└── test.sh
/.flake8:
--------------------------------------------------------------------------------
1 | [flake8]
2 | filename =
3 | *.py,
4 | *.py.in,
5 | */src/insights-client.in,
6 | # same limit as black
7 | max-line-length = 88
8 | ignore =
9 | # E203 whitespace before ':'
10 | # result of black-formatted code
11 | E203,
12 | # W503: line break before binary operator
13 | W503
14 | extend-exclude =
15 | # default build directory
16 | build/,
17 |
--------------------------------------------------------------------------------
/.fmf/version:
--------------------------------------------------------------------------------
1 | 1
2 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: "github-actions"
4 | directory: "/"
5 | schedule:
6 | interval: "weekly"
7 | target-branch: "master"
8 | commit-message:
9 | prefix: "ci"
10 |
--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | ---
2 |
3 |
4 |
11 |
12 |
15 |
16 |
20 |
--------------------------------------------------------------------------------
/.github/workflows/codespell.yml:
--------------------------------------------------------------------------------
1 | name: codespell
2 |
3 | on:
4 | pull_request:
5 | workflow_dispatch:
6 |
7 | jobs:
8 | codespell:
9 | runs-on: "ubuntu-latest"
10 |
11 | steps:
12 | - uses: actions/checkout@v4
13 |
14 | - uses: codespell-project/actions-codespell@v2
15 |
--------------------------------------------------------------------------------
/.github/workflows/docstring_validation.yml:
--------------------------------------------------------------------------------
1 | ---
2 | name: Test Docstrings Validation
3 |
4 | on:
5 | pull_request:
6 | paths:
7 | - "integration-tests/**"
8 |
9 | jobs:
10 | betelgeuse:
11 | name: "betelgeuse dry-run"
12 | runs-on: ubuntu-latest
13 | container:
14 | image: fedora:latest
15 |
16 | steps:
17 | - uses: actions/checkout@v4
18 |
19 | - name: Base setup for Betelgeuse
20 | run: |
21 | dnf --setopt install_weak_deps=False install -y \
22 | python3-pip
23 | python3 -m pip install betelgeuse
24 |
25 | - name: Run Betelgeuse
26 | run: |
27 | PYTHONPATH=integration-tests/ betelgeuse --config-module \
28 | custom_betelgeuse_config test-case --dry-run \
29 | integration-tests/ dryrun_project ./test_case.xml
30 |
--------------------------------------------------------------------------------
/.github/workflows/pytest.yml:
--------------------------------------------------------------------------------
1 | name: pytest
2 |
3 | on:
4 | pull_request:
5 | paths:
6 | - "src/**"
7 | - ".github/workflows/pytest.yml"
8 |
9 | jobs:
10 | pytest:
11 | strategy:
12 | fail-fast: false
13 | matrix:
14 | include:
15 | - name: "Fedora Rawhide"
16 | image: "registry.fedoraproject.org/fedora:rawhide"
17 | - name: "Fedora Latest"
18 | image: "registry.fedoraproject.org/fedora:latest"
19 | - name: "CentOS Stream 10"
20 | image: "quay.io/centos/centos:stream10"
21 |
22 | runs-on: "ubuntu-latest"
23 | container:
24 | image: ${{ matrix.image }}
25 |
26 | steps:
27 | - name: "Checkout the repository"
28 | uses: actions/checkout@v4
29 |
30 | - name: "Install dependencies"
31 | run: |
32 | dnf --setopt install_weak_deps=False install -y git-core python3-pip gpg
33 | python3 -m pip install --upgrade pip wheel
34 | python3 -m pip install -r src/insights_client/tests/requirements.txt
35 |
36 | - name: "Run pytest"
37 | env:
38 | PYTEST_ADDOPTS: "--color=yes --code-highlight=yes --showlocals"
39 | run: |
40 | python3 -m pytest src/insights_client/tests
41 |
--------------------------------------------------------------------------------
/.github/workflows/stylish.yml:
--------------------------------------------------------------------------------
1 | name: stylish
2 |
3 | on:
4 | pull_request:
5 | workflow_dispatch:
6 |
7 | jobs:
8 | stylish:
9 | name: "black & flake8"
10 | runs-on: ubuntu-latest
11 | container:
12 | image: fedora:latest
13 |
14 | steps:
15 | - name: Base setup
16 | run: |
17 | dnf --setopt install_weak_deps=False install -y \
18 | git-core \
19 | python3-flake8 \
20 | python3-pip
21 |
22 | - uses: actions/checkout@v4
23 |
24 | - uses: psf/black@stable
25 | with:
26 | version: "24.3.0"
27 |
28 | - name: Setup flake8 annotations
29 | uses: rbialon/flake8-annotations@v1
30 |
31 | - name: Run flake8
32 | run: |
33 | flake8
34 |
--------------------------------------------------------------------------------
/.github/workflows/testimony.yml:
--------------------------------------------------------------------------------
1 | ---
2 | name: Testimony Validation
3 |
4 | on:
5 | pull_request:
6 | paths:
7 | - "integration-tests/**"
8 |
9 | jobs:
10 | testimony:
11 | name: testimony validate
12 | runs-on: ubuntu-latest
13 | container:
14 | image: fedora:latest
15 |
16 | steps:
17 | - name: Setup for Testimony
18 | run: |
19 | dnf --setopt install_weak_deps=False install -y \
20 | python3-pip
21 | python3 -m pip install testimony
22 | - uses: actions/checkout@v4
23 |
24 | - name: Run Testimony
25 | run: |
26 | testimony validate --config \
27 | integration-tests/testimony.yml integration-tests/test*
28 |
--------------------------------------------------------------------------------
/.gitleaks.toml:
--------------------------------------------------------------------------------
1 | [extend]
2 | useDefault = true
3 |
4 |
5 | [allowlist]
6 | description = "Repository-specific configuration"
7 |
8 | paths = [
9 | # Tests for insights-core contain public and private GPG keypair. They were
10 | # generated specifically for this usecase.
11 | "systemtest/insights-core-setup.sh",
12 | ]
13 |
--------------------------------------------------------------------------------
/.packit.yaml:
--------------------------------------------------------------------------------
1 | upstream_package_name: insights-client
2 | downstream_package_name: insights-client
3 | specfile_path: out/insights-client.spec
4 |
5 | srpm_build_deps:
6 | - gawk
7 | - rpkg
8 |
9 | actions:
10 | post-upstream-clone:
11 | - mkdir out
12 | - rpkg srpm --outdir out
13 | get-current-version:
14 | - awk '/^Version:/ {print $2;}' out/insights-client.spec
15 | create-archive:
16 | - bash -c 'echo out/insights-client-*.tar.*'
17 | fix-spec-file:
18 | - echo 'nothing to fix'
19 |
20 | jobs:
21 | - job: copr_build
22 | trigger: pull_request
23 | targets:
24 | - centos-stream-10-x86_64
25 | - centos-stream-10-aarch64
26 | - centos-stream-10-s390x
27 | - centos-stream-10-ppc64le
28 | - fedora-all
29 |
30 | - job: copr_build
31 | trigger: commit
32 | branch: master
33 | owner: "@yggdrasil"
34 | project: latest
35 | targets:
36 | - centos-stream-10-x86_64
37 | - centos-stream-10-aarch64
38 | - centos-stream-10-s390x
39 | - centos-stream-10-ppc64le
40 | - fedora-all
41 |
42 | - job: tests
43 | trigger: pull_request
44 | identifier: "unit/centos-stream"
45 | targets:
46 | - centos-stream-10-x86_64
47 | labels:
48 | - unit
49 | tf_extra_params:
50 | environments:
51 | - artifacts:
52 | - type: repository-file
53 | id: https://copr.fedorainfracloud.org/coprs/g/yggdrasil/latest/repo/centos-stream-$releasever/group_yggdrasil-latest-centos-stream-$releasever.repo
54 |
55 | - job: tests
56 | trigger: pull_request
57 | identifier: "unit/fedora"
58 | targets:
59 | - fedora-all
60 | labels:
61 | - unit
62 | tf_extra_params:
63 | environments:
64 | - artifacts:
65 | - type: repository-file
66 | id: https://copr.fedorainfracloud.org/coprs/g/yggdrasil/latest/repo/fedora-$releasever/group_yggdrasil-latest-fedora-$releasever.repo
67 |
68 | - job: tests
69 | trigger: pull_request
70 | identifier: "unit/rhel"
71 | targets:
72 | centos-stream-10-x86_64: # TODO: Change back to RHEL
73 | distros:
74 | - RHEL-10-Nightly
75 | labels:
76 | - unit
77 | tf_extra_params:
78 | environments:
79 | - artifacts:
80 | - type: repository-file
81 | id: https://copr.fedorainfracloud.org/coprs/g/yggdrasil/latest/repo/rhel-$releasever/group_yggdrasil-latest-rhel-$releasever.repo
82 | settings:
83 | provisioning:
84 | tags:
85 | BusinessUnit: sst_csi_client_tools
86 | use_internal_tf: true
87 |
--------------------------------------------------------------------------------
/.sourcery.yaml:
--------------------------------------------------------------------------------
1 | rule_settings:
2 | enable: [default]
3 | disable:
4 | - no-loop-in-tests
5 | - no-conditionals-in-tests
6 |
--------------------------------------------------------------------------------
/.testing-farm.yaml:
--------------------------------------------------------------------------------
1 | version: 1
2 |
3 | environments:
4 | secrets:
5 | SETTINGS_URL: "ea2a89aa-6a78-40e0-906e-140f623c45b0,qdeC9UxsCJa8e4UA/873Bv41RgSaYlbmFWz97gNEkiFjgxBF5wQiZGD3KDgki110oOXmAb4Ty0haFAi7XB2SAZvA7ooXRxrVRP/U3dyxNir5uYmHRurBx+pqb05eOn2zmygqqyTthXNglRvg2kJnjuYB44h4W/u2VUl8Id+s4h67IaX15toY3VKr3vmdH2OxFMUI6U/atyd6Z96jqP0muxhu+KuYv40nYUrgiFqoOedom0DOCPCMQUubeYQ3mexcc0HF/L28bbyt1eFNWYYuSXb61/Gjg3s2Shw7e7RhWquqsvzWlCTa0JFalGD+uELgVxOjwHDbn56drnnjh3oVcpD20YTQQbsAGHCgPhqCuxkqCe9ayIvKKCsYKapdQ+D0NvjXFRyj2QfFrOdQHf4KUOD6MXBWAOswM/3C6x+zj6O5YZTSmMagq1oLgeG2wqhL56zNUGoxqgcRv9MYmgPzbiF6SPlAniMwWjjcDNsmWhMAoJDAI5q7+Tazjs7OvziUsEgMp1T4jZooIdHtAU+ily4K8Gf8lPiQHhxFD1ieC9E1xzBeVuh+tHhuB7E6WN+sISzxXdyUDTd5lyZicqgxJ/GmEjB2K+/MDDW1VI9Yyk6Ee3iUVGGBktvaF0eV4WqrNPv8AAJL/RMDU+T/grUTmf703DQFNWPyISAJDuw8h+Y="
6 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (C) 2015 Red Hat Inc.
2 |
3 | This program is free software: you can redistribute it and/or modify
4 | it under the terms of the GNU General Public License as published by
5 | the Free Software Foundation, either version 3 of the License, or
6 | (at your option) any later version.
7 |
8 | This program is distributed in the hope that it will be useful,
9 | but WITHOUT ANY WARRANTY; without even the implied warranty of
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 | GNU General Public License for more details.
12 |
13 | You should have received a copy of the GNU General Public License
14 | along with this program. If not, see .
15 |
--------------------------------------------------------------------------------
/TESTING.md:
--------------------------------------------------------------------------------
1 | # Testing `insights-client`
2 |
3 | After installing the prerequisites, you can run the unit test suite using `pytest`:
4 |
5 | ```shell
6 | $ python3 -m pip install -r src/insights_client/tests/requirements.txt
7 | $ python3 -m pytest src/insights_client/tests
8 | ```
9 |
10 | ## Specifying the egg
11 |
12 | By default, we are using the `rpm.egg` to run insights-client test suite.
13 | By pointing the `EGG` environment variable to a different path, you can test custom eggs (the upstream HEAD, for example).
14 |
15 |
16 | ## CI
17 |
18 | The unit tests are also run by GitHub Actions.
19 |
--------------------------------------------------------------------------------
/data/.exp.sed:
--------------------------------------------------------------------------------
1 | s/(password[a-zA-Z0-9_]*)(\s*\:\s*\"*\s*|\s*\"*\s*=\s*\"\s*|\s*=+\s*|\s*--md5+\s*|\s*)([a-zA-Z0-9_!@#$%^&*()+=/-]+)/\1\2********/
2 | s/(password[a-zA-Z0-9_]*)(\s*\*+\s+)(.+)/\1\2********/
3 |
--------------------------------------------------------------------------------
/data/cert-api.access.redhat.com.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIHZDCCBUygAwIBAgIJAOb+QiglyeZeMA0GCSqGSIb3DQEBBQUAMIGwMQswCQYD
3 | VQQGEwJVUzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExEDAOBgNVBAcMB1JhbGVp
4 | Z2gxFjAUBgNVBAoMDVJlZCBIYXQsIEluYy4xGDAWBgNVBAsMD1JlZCBIYXQgTmV0
5 | d29yazEeMBwGA1UEAwwVRW50aXRsZW1lbnQgTWFzdGVyIENBMSQwIgYJKoZIhvcN
6 | AQkBFhVjYS1zdXBwb3J0QHJlZGhhdC5jb20wHhcNMTAwMzE3MTkwMDQ0WhcNMzAw
7 | MzEyMTkwMDQ0WjCBsDELMAkGA1UEBhMCVVMxFzAVBgNVBAgMDk5vcnRoIENhcm9s
8 | aW5hMRAwDgYDVQQHDAdSYWxlaWdoMRYwFAYDVQQKDA1SZWQgSGF0LCBJbmMuMRgw
9 | FgYDVQQLDA9SZWQgSGF0IE5ldHdvcmsxHjAcBgNVBAMMFUVudGl0bGVtZW50IE1h
10 | c3RlciBDQTEkMCIGCSqGSIb3DQEJARYVY2Etc3VwcG9ydEByZWRoYXQuY29tMIIC
11 | IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA2Z+mW7OYcBcGxWS+RSKG2GJ2
12 | csMXiGGfEp36vKVsIvypmNS60SkicKENMYREalbdSjrgfXxPJygZWsVWJ5lHPfBV
13 | o3WkFrFHTIXd/R6LxnaHD1m8Cx3GwEeuSlE/ASjc1ePtMnsHH7xqZ9wdl85b1C8O
14 | scgO7fwuM192kvv/veI/BogIqUQugtG6szXpV8dp4ml029LXFoNIy2lfFoa2wKYw
15 | MiUHwtYgAz7TDY63e8qGhd5PoqTv9XKQogo2ze9sF9y/npZjliNy5qf6bFE+24oW
16 | E8pGsp3zqz8h5mvw4v+tfIx5uj7dwjDteFrrWD1tcT7UmNrBDWXjKMG81zchq3h4
17 | etgF0iwMHEuYuixiJWNzKrLNVQbDmcLGNOvyJfq60tM8AUAd72OUQzivBegnWMit
18 | CLcT5viCT1AIkYXt7l5zc/duQWLeAAR2FmpZFylSukknzzeiZpPclRziYTboDYHq
19 | revM97eER1xsfoSYp4mJkBHfdlqMnf3CWPcNgru8NbEPeUGMI6+C0YvknPlqDDtU
20 | ojfl4qNdf6nWL+YNXpR1YGKgWGWgTU6uaG8Sc6qGfAoLHh6oGwbuz102j84OgjAJ
21 | DGv/S86svmZWSqZ5UoJOIEqFYrONcOSgztZ5tU+gP4fwRIkTRbTEWSgudVREOXhs
22 | bfN1YGP7HYvS0OiBKZUCAwEAAaOCAX0wggF5MB0GA1UdDgQWBBSIS6ZFxEbsj9bP
23 | pvYazyY8kMx/FzCB5QYDVR0jBIHdMIHagBSIS6ZFxEbsj9bPpvYazyY8kMx/F6GB
24 | tqSBszCBsDELMAkGA1UEBhMCVVMxFzAVBgNVBAgMDk5vcnRoIENhcm9saW5hMRAw
25 | DgYDVQQHDAdSYWxlaWdoMRYwFAYDVQQKDA1SZWQgSGF0LCBJbmMuMRgwFgYDVQQL
26 | DA9SZWQgSGF0IE5ldHdvcmsxHjAcBgNVBAMMFUVudGl0bGVtZW50IE1hc3RlciBD
27 | QTEkMCIGCSqGSIb3DQEJARYVY2Etc3VwcG9ydEByZWRoYXQuY29tggkA5v5CKCXJ
28 | 5l4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAQYwEQYJYIZIAYb4QgEBBAQDAgEG
29 | MCAGA1UdEQQZMBeBFWNhLXN1cHBvcnRAcmVkaGF0LmNvbTAgBgNVHRIEGTAXgRVj
30 | YS1zdXBwb3J0QHJlZGhhdC5jb20wDQYJKoZIhvcNAQEFBQADggIBAJ1hEdNBDTRr
31 | 6kI6W6stoogSUwjuiWPDY8DptwGhdpyIfbCoxvBR7F52DlwyXOpCunogfKMRklnE
32 | gH1Wt66RYkgNuJcenKHAhR5xgSLoPCOVF9rDjMunyyBuxjIbctM21R7BswVpsEIE
33 | OpV5nlJ6wkHsrn0/E+Zk5UJdCzM+Fp4hqHtEn/c97nvRspQcpWeDg6oUvaJSZTGM
34 | 8yFpzR90X8ZO4rOgpoERukvYutUfJUzZuDyS3LLc6ysamemH93rZXr52zc4B+C9G
35 | Em8zemDgIPaH42ce3C3TdVysiq/yk+ir7pxW8toeavFv75l1UojFSjND+Q2AlNQn
36 | pYkmRznbD5TZ3yDuPFQG2xYKnMPACepGgKZPyErtOIljQKCdgcvb9EqNdZaJFz1+
37 | /iWKYBL077Y0CKwb+HGIDeYdzrYxbEd95YuVU0aStnf2Yii2tLcpQtK9cC2+DXjL
38 | Yf3kQs4xzH4ZejhG9wzv8PGXOS8wHYnfVNA3+fclDEQ1mEBKWHHmenGI6QKZUP8f
39 | g0SQ3PNRnSZu8R+rhABOEuVFIBRlaYijg2Pxe0NgL9FlHsNyRfo6EUrB2QFRKACW
40 | 3Mo6pZyDjQt7O8J7l9B9IIURoJ1niwygf7VSJTMl2w3fFleNJlZTGgdXw0V+5g+9
41 | Kg6Ay0rrsi4nw1JHue2GvdjdfVOaWSWC
42 | -----END CERTIFICATE-----
43 | -----BEGIN CERTIFICATE-----
44 | MIIFfTCCA2WgAwIBAgIJAJGKz8qFAAADMA0GCSqGSIb3DQEBBQUAMIGwMQswCQYD
45 | VQQGEwJVUzEXMBUGA1UECAwOTm9ydGggQ2Fyb2xpbmExEDAOBgNVBAcMB1JhbGVp
46 | Z2gxFjAUBgNVBAoMDVJlZCBIYXQsIEluYy4xGDAWBgNVBAsMD1JlZCBIYXQgTmV0
47 | d29yazEeMBwGA1UEAwwVRW50aXRsZW1lbnQgTWFzdGVyIENBMSQwIgYJKoZIhvcN
48 | AQkBFhVjYS1zdXBwb3J0QHJlZGhhdC5jb20wHhcNMTUwNTA1MTMwMzQ4WhcNMjUw
49 | NTAyMTMwMzQ4WjCBiTELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5PUlRIIENBUk9M
50 | SU5BMRAwDgYDVQQHEwdSYWxlaWdoMRAwDgYDVQQKEwdSZWQgSGF0MRgwFgYDVQQL
51 | Ew9SZWQgSGF0IE5ldHdvcmsxIzAhBgNVBAMTGmNlcnQtYXBpLmFjY2Vzcy5yZWRo
52 | YXQuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA9hTNMtZMa7Kg
53 | Jlux6pnuUinP0Rv0aiiPFr7qNHFore4loGrPlpzUvQbUByy3xm7lhf4R4qbINCls
54 | veWg6HDidvQr174RXb5YLMXuBrYAiPWQTrRRLNuvXFHKzREghRWTv48IXTIDEo0G
55 | fZJUO+myY2RfwqugZKic5dR6ZakHSSpQO70O6H5R0eHlKa13k4eEpG2fVY/xqFto
56 | WkfZyEmSacZpqxp7gIjZqreLc4MFwpiVjGFrK3Jk+Px1Z6J94LTLx2SxrYzWIeUs
57 | 5j+lceQOvpV4/pkClnRCW1pkCKTccjFKQkpNPGwdIusRXUGl9IYc20Fa/7g9iUQc
58 | 5fXu9EAzfwIDAQABo4G+MIG7MAkGA1UdEwQCMAAwEQYJYIZIAYb4QgEBBAQDAgZA
59 | MAsGA1UdDwQEAwIF4DATBgNVHSUEDDAKBggrBgEFBQcDATA5BglghkgBhvhCAQ0E
60 | LBYqTWFuYWdlZCBieSBSZWQgSGF0IChjYS1zdXBwb3J0QHJlZGhhdC5jb20pMB0G
61 | A1UdDgQWBBRfgCjd8aXf0U4VX8DKTVIn+paGBzAfBgNVHSMEGDAWgBSIS6ZFxEbs
62 | j9bPpvYazyY8kMx/FzANBgkqhkiG9w0BAQUFAAOCAgEAlC+r6UEEp5BUkI0Rj2T+
63 | 1PH7oUCaGQeQoyVbGddz/WUcBk/lMMtyCEoxU+3tTwNWmCWWjYXtjoL9MlSAC/q+
64 | NZfBi1iq0uuSus9JI/Uu8aRhoxTK56qGRed/JNixOHEmFn891cahIPpF0exWwtYD
65 | ThwXo7Z6PI7t8EMKdSrGTOowp58yho8xYFL/Z7JmjL55Pf85GIrdiniNZd4i178J
66 | 07R9zsiLvdXq9mT33iJwkm+uhO+FA9d8OE3ji21pBbGUAQSWOdkemvUCsy8zANW9
67 | fT+dBrMr5Buk7eaBBJ2PxECNiWLCRQJWmyff1O5zMT0daS2lBdEGUNhBZ0hnX13Q
68 | kabUp0bxRrNRq+WkomP7onZhfZS6SjKm0UmwoV6o3V1ED6y7muQNRmgDpA5PcbvO
69 | gl7OexNL4zcpyfMdAmTYf5yTRSvB42Yg5hVfuzPEnOIqupwES3mWkEHRlqbMUkHw
70 | qIQAxIwQqZd5PdPpElQ/6j/ZT9DwW/I6zgndX2rsS0oGYcwFTkSj0/rKKkC13hk7
71 | LchXMZu5ckdustM79U6OZIBairrJaL2OpR08un2nwIjgEGqhVFYc44UK1VpkE8mr
72 | qvqJS6OHVlTlKcEDnhVkPS3i5qjuS/PtSq0CwH8bzYKFJayLDY/z36Zv6PdttzmU
73 | Yb1NSDcJejHJ80pMINutyYQ=
74 | -----END CERTIFICATE-----
75 |
--------------------------------------------------------------------------------
/data/insights-client.conf:
--------------------------------------------------------------------------------
1 | [insights-client]
2 | # Example options in this file are the defaults
3 |
4 | # Change log level, valid options DEBUG, INFO, WARNING, ERROR, CRITICAL. Default DEBUG
5 | #loglevel=DEBUG
6 |
7 | # Attempt to auto configure with Satellite server
8 | #auto_config=True
9 |
10 | # Base URL for the Insights API
11 | #base_url=cert-api.access.redhat.com:443/r/insights
12 |
13 | # URL for your proxy. Example: http://user:pass@192.168.100.50:8080
14 | #proxy=
15 |
16 | # Automatically update the dynamic configuration
17 | #auto_update=True
18 |
19 | # Obfuscate IP addresses
20 | #obfuscate=False
21 |
22 | # Obfuscate hostname. Requires obfuscate=True.
23 | #obfuscate_hostname=False
24 |
25 | # Display name for registration
26 | #display_name=
27 |
28 | # Ansible hostname for this system
29 | #ansible_host=
30 |
31 | # Timeout for commands run during collection, in seconds
32 | #cmd_timeout=120
33 |
34 | # Timeout for HTTP calls, in seconds
35 | #http_timeout=120
36 |
37 | # Location of the redaction file for commands, files, and components
38 | #redaction_file=/etc/insights-client/file-redaction.yaml
39 |
40 | # Location of the redaction file for patterns and keywords
41 | #content_redaction_file=/etc/insights-client/file-content-redaction.yaml
42 |
43 | # Location of the tags file for this system
44 | #tags_file=/etc/insights-client/tags.yaml
45 |
--------------------------------------------------------------------------------
/data/insights-client.motd:
--------------------------------------------------------------------------------
1 | Register this system with Red Hat Insights: rhc connect
2 |
3 | Example:
4 | # rhc connect --activation-key --organization
5 |
6 | The rhc client and Red Hat Insights will enable analytics and additional
7 | management capabilities on your system.
8 | View your connected systems at https://console.redhat.com/insights
9 |
10 | You can learn more about how to register your system
11 | using rhc at https://red.ht/registration
12 |
--------------------------------------------------------------------------------
/data/logrotate.d/insights-client:
--------------------------------------------------------------------------------
1 | /var/log/insights-client/*.log {
2 | rotate 4
3 | weekly
4 | missingok
5 | notifempty
6 | copytruncate
7 | }
8 |
--------------------------------------------------------------------------------
/data/logrotate.d/meson.build:
--------------------------------------------------------------------------------
1 | install_data(
2 | ['insights-client'],
3 | install_dir: get_option('sysconfdir') / 'logrotate.d'
4 | )
5 |
--------------------------------------------------------------------------------
/data/meson.build:
--------------------------------------------------------------------------------
1 | sysconf_sources = [
2 | '.exp.sed',
3 | 'cert-api.access.redhat.com.pem',
4 | 'insights-client.conf',
5 | 'insights-client.motd',
6 | 'redhattools.pub.gpg',
7 | 'rpm.egg',
8 | 'rpm.egg.asc'
9 | ]
10 |
11 | install_data(
12 | sysconf_sources,
13 | install_dir: get_option('sysconfdir') / 'insights-client'
14 | )
15 |
16 | subdir('logrotate.d')
17 | subdir('systemd')
18 | subdir('tmpfiles.d')
19 |
--------------------------------------------------------------------------------
/data/redhattools.pub.gpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RedHatInsights/insights-client/cfe9826192b6369d61b4d20f91321795c8adb93a/data/redhattools.pub.gpg
--------------------------------------------------------------------------------
/data/rpm.egg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RedHatInsights/insights-client/cfe9826192b6369d61b4d20f91321795c8adb93a/data/rpm.egg
--------------------------------------------------------------------------------
/data/rpm.egg.asc:
--------------------------------------------------------------------------------
1 | -----BEGIN PGP SIGNATURE-----
2 | Version: GnuPG v1
3 |
4 | iQIcBAABCAAGBQJoCfbwAAoJEHUU932DZrDZScwP/17zbBToA/d1Gzvq/v/QDp/c
5 | kNy9YMQwEAe1vF9FfB2j+OKulfQIqrIQoC9PADND1Ut0PaEW4As1sJEVot/kA6vk
6 | EU4+L6eEOAhI0SdozvKmGWxbtctYiwSRRnO/rqUR0NjFQpj+mVj7doRuL1OUUA3U
7 | 82o7bdZmvwsViS5bTvR8dZ5eTS4zLgZA3p7Bh4tjMdZZkzE2Ndq7+R6Y3z8glHVD
8 | auPkOR0/xXttDzT/7H9D+d5AFVdtOM42HGHi5x0wkiLp+Kq+DG7tXUCghvIXdY2c
9 | dQWV0yhecizSap9Ph6yF3/DK68xidMrIlXtzfpXyrzCYLUQiONDGsy+0JLwenHjt
10 | hjI5iRu4g3zok5dLbDQGam/ZbNe7ngvZT384tsjEVr6lx/TsH5H8C9EbDdxxCHnj
11 | rbOkoX0kEdd6SCUBRsczFOFIgglHaoF+PPwofuD/8GCoL4lRuQd21ouPq2YuLYbg
12 | HltcH5PCvvqKhZYHbCUIBuKf5Or+OnexBx/i17vC6SmSeXsmhPSxLeq9yu+XuyG+
13 | DaAGVXeTHN1j9p/VxEpNQ0Kul2dymbCQNH6EMvg06mUGCgjCLA4YCposmx69PpJR
14 | F3PmmlNyFsd6R0D0ArfyleCvxwJeqGnsbRPPOtFYtHCweorYbVhbO/UTYA2hvltS
15 | Iasitn7L+jxs2B5+qz3R
16 | =mCaM
17 | -----END PGP SIGNATURE-----
18 |
--------------------------------------------------------------------------------
/data/systemd/80-insights-register.preset:
--------------------------------------------------------------------------------
1 | enable insights-register.path
2 | enable insights-unregister.path
3 |
--------------------------------------------------------------------------------
/data/systemd/80-insights.preset:
--------------------------------------------------------------------------------
1 | enable insights-client-boot.service
2 |
--------------------------------------------------------------------------------
/data/systemd/insights-client-boot.service:
--------------------------------------------------------------------------------
1 | # This file is part of insights-client.
2 | #
3 | # Any changes made to this file will be overwritten during a software update. To
4 | # override a parameter in this file, create a drop-in file, typically located at
5 | # /etc/systemd/system/insights-client-boot.service.d/override.conf Put the desired
6 | # overrides in that file and reload systemd.
7 | #
8 | # For more information about systemd drop-in files, see systemd.unit(5).
9 |
10 | [Unit]
11 | Description=Run Insights Client at boot
12 | Documentation=man:insights-client(8)
13 | After=network-online.target
14 | ConditionPathExists=/etc/insights-client/.run_insights_client_next_boot
15 |
16 | [Service]
17 | Type=oneshot
18 | ExecStart=/usr/bin/insights-client --retry 3
19 | Restart=no
20 | WatchdogSec=900
21 | CPUQuota=30%
22 | MemoryHigh=1G
23 | MemoryMax=2G
24 | TasksMax=300
25 | BlockIOWeight=100
26 | ExecStartPre=/bin/rm -f /etc/insights-client/.run_insights_client_next_boot
27 |
28 | [Install]
29 | WantedBy=multi-user.target
30 |
--------------------------------------------------------------------------------
/data/systemd/insights-client-checkin.service.in:
--------------------------------------------------------------------------------
1 | # This file is part of insights-client.
2 | #
3 | # Any changes made to this file will be overwritten during a software update. To
4 | # override a parameter in this file, create a drop-in file, typically located at
5 | # /etc/systemd/system/insights-client-results.service.d/override.conf. Put the
6 | # desired overrides in that file and reload systemd. The next time this service
7 | # is run (either manually or via another systemd unit), the overridden values
8 | # will be in effect.
9 | #
10 | # For more information about systemd drop-in files, see systemd.unit(5).
11 |
12 | [Unit]
13 | Description=Check-in with the platform
14 | Documentation=man:insights-client(8)
15 | After=network-online.target
16 | Wants=network-online.target
17 |
18 | [Service]
19 | Type=oneshot
20 | RemainAfterExit=no
21 | ExecStart=@bindir@/insights-client --checkin
22 | Restart=no
23 |
--------------------------------------------------------------------------------
/data/systemd/insights-client-checkin.timer:
--------------------------------------------------------------------------------
1 | # This file is part of insights-client.
2 | #
3 | # Any changes made to this file will be overwritten during a software update. To
4 | # override a parameter in this file, create a drop-in file, typically located at
5 | # /etc/systemd/system/insights-client.timer.d/override.conf. Put the desired
6 | # overrides in that file, reload systemd and restart this timer.
7 | #
8 | # For more information about systemd drop-in files, see systemd.unit(5).
9 |
10 | [Unit]
11 | Description=Check-in with the platform timer
12 | Documentation=man:insights-client(8)
13 | After=network-online.target
14 | Wants=network-online.target
15 |
16 | [Timer]
17 | OnCalendar=hourly
18 | Persistent=true
19 | RandomizedDelaySec=600
20 |
21 | [Install]
22 | WantedBy=timers.target
23 |
--------------------------------------------------------------------------------
/data/systemd/insights-client-results.path.in:
--------------------------------------------------------------------------------
1 | # This file is part of insights-client.
2 | #
3 | # Any changes made to this file will be overwritten during a software update. To
4 | # override a parameter in this file, create a drop-in file, typically located at
5 | # /etc/systemd/system/insights-client-results.path.d/override.conf. Put the
6 | # desired overrides in that file and reload systemd.
7 | #
8 | # For more information about systemd drop-in files, see systemd.unit(5).
9 |
10 | [Unit]
11 | Description=Monitor @pkgsysconfdir@/.lastupload for modifications
12 | Documentation=man:insights-client(8)
13 | PartOf=insights-client.timer
14 |
15 | [Path]
16 | PathModified=@pkgsysconfdir@/.lastupload
17 |
18 | [Install]
19 | WantedBy=insights-client.timer
20 |
--------------------------------------------------------------------------------
/data/systemd/insights-client-results.service.in:
--------------------------------------------------------------------------------
1 | # This file is part of insights-client.
2 | #
3 | # Any changes made to this file will be overwritten during a software update. To
4 | # override a parameter in this file, create a drop-in file, typically located at
5 | # /etc/systemd/system/insights-client-results.service.d/override.conf. Put the
6 | # desired overrides in that file and reload systemd. The next time this service
7 | # is run (either manually or via another systemd unit), the overridden values
8 | # will be in effect.
9 | #
10 | # For more information about systemd drop-in files, see systemd.unit(5).
11 |
12 | [Unit]
13 | Description=Check for insights from Red Hat Cloud Services
14 | Documentation=man:insights-client(8)
15 | After=network-online.target
16 |
17 | [Service]
18 | Type=oneshot
19 | RemainAfterExit=no
20 | ExecStart=@bindir@/insights-client --check-results
21 | Restart=no
22 |
--------------------------------------------------------------------------------
/data/systemd/insights-client.service:
--------------------------------------------------------------------------------
1 | # This file is part of insights-client.
2 | #
3 | # Any changes made to this file will be overwritten during a software update. To
4 | # override a parameter in this file, create a drop-in file, typically located at
5 | # /etc/systemd/system/insights-client.service.d/override.conf. Put the desired
6 | # overrides in that file and reload systemd. The next time this service is run
7 | # (either manually or via a systemd timer), the overridden values will be in
8 | # effect.
9 | #
10 | # For more information about systemd drop-in files, see systemd.unit(5).
11 |
12 | [Unit]
13 | Description=Insights Client
14 | Documentation=man:insights-client(8)
15 | After=network.target
16 | StartLimitIntervalSec=12h
17 | StartLimitBurst=6
18 |
19 | [Service]
20 | Type=exec
21 | ExecStart=/usr/bin/insights-client
22 | Restart=on-failure
23 | RestartSec=1h
24 | WatchdogSec=900
25 | CPUQuota=30%
26 | MemoryHigh=1G
27 | MemoryMax=2G
28 | TasksMax=300
29 | BlockIOWeight=100
30 |
--------------------------------------------------------------------------------
/data/systemd/insights-client.timer:
--------------------------------------------------------------------------------
1 | # This file is part of insights-client.
2 | #
3 | # Any changes made to this file will be overwritten during a software update. To
4 | # override a parameter in this file, create a drop-in file, typically located at
5 | # /etc/systemd/system/insights-client.timer.d/override.conf. Put the desired
6 | # overrides in that file, reload systemd and restart this timer.
7 | #
8 | # For more information about systemd drop-in files, see systemd.unit(5).
9 |
10 | [Unit]
11 | Description=Insights Client Timer Task
12 | Documentation=man:insights-client(8)
13 | After=network-online.target
14 | Wants=network-online.target
15 |
16 | [Timer]
17 | OnCalendar=daily
18 | Persistent=true
19 | RandomizedDelaySec=14400
20 |
21 | [Install]
22 | WantedBy=timers.target
23 | Also=insights-client-results.path
24 |
--------------------------------------------------------------------------------
/data/systemd/insights-register.path.in:
--------------------------------------------------------------------------------
1 | # This file is part of insights-client.
2 | #
3 | # Any changes made to this file will be overwritten during a software update. To
4 | # override a parameter in this file, create a drop-in file, typically located at
5 | # /etc/systemd/system/insights-register.path.d/override.conf. Put the desired
6 | # overrides in that file and reload systemd.
7 | #
8 | # For more information about systemd drop-in files, see systemd.unit(5).
9 |
10 | [Unit]
11 | Description=Automatically Register with Red Hat Insights Path Watch
12 | Documentation=man:insights-client(8)
13 |
14 | [Path]
15 | PathExists=@sysconfdir@/pki/consumer/cert.pem
16 |
17 | [Install]
18 | WantedBy=multi-user.target
19 |
--------------------------------------------------------------------------------
/data/systemd/insights-register.service.in:
--------------------------------------------------------------------------------
1 | # This file is part of insights-client.
2 | #
3 | # Any changes made to this file will be overwritten during a software update. To
4 | # override a parameter in this file, create a drop-in file, typically located at
5 | # /etc/systemd/system/insights-register.service.d/override.conf. Put the desired
6 | # overrides in that file and reload systemd. The next time this service is run
7 | # (either manually or via a systemd timer), the overridden values will be in
8 | # effect.
9 | #
10 | # For more information about systemd drop-in files, see systemd.unit(5).
11 |
12 | [Unit]
13 | Description=Automatically Register with Red Hat Insights
14 | Documentation=man:insights-client(8)
15 | After=network-online.target
16 |
17 | [Service]
18 | Type=simple
19 | ExecStart=@bindir@/insights-client --register
20 | Restart=no
21 | WatchdogSec=900
22 | CPUQuota=30%
23 | MemoryHigh=1G
24 | MemoryMax=2G
25 | TasksMax=300
26 | BlockIOWeight=100
27 | ExecStopPost=systemctl mask --now insights-register.path
28 |
--------------------------------------------------------------------------------
/data/systemd/insights-unregister.path.in:
--------------------------------------------------------------------------------
1 | # This file is part of insights-client.
2 | #
3 | # Any changes made to this file will be overwritten during a software update. To
4 | # override a parameter in this file, create a drop-in file, typically located at
5 | # /etc/systemd/system/insights-unregister.path.d/override.conf. Put the desired
6 | # overrides in that file and reload systemd.
7 | #
8 | # For more information about systemd drop-in files, see systemd.unit(5).
9 |
10 | [Unit]
11 | Description=Automatically Unregister from Red Hat Insights Path Watch
12 | Documentation=man:insights-client(8)
13 |
14 | [Path]
15 | PathChanged=@sysconfdir@/pki/consumer/cert.pem
16 |
17 | [Install]
18 | WantedBy=multi-user.target
19 |
--------------------------------------------------------------------------------
/data/systemd/insights-unregister.service.in:
--------------------------------------------------------------------------------
1 | # This file is part of insights-client.
2 | #
3 | # Any changes made to this file will be overwritten during a software update. To
4 | # override a parameter in this file, create a drop-in file, typically located at
5 | # /etc/systemd/system/insights-unregister.service.d/override.conf. Put the
6 | # desired overrides in that file and reload systemd. The next time this service
7 | # is run (either manually or via a systemd timer), the overridden values will be
8 | # in effect.
9 | #
10 | # For more information about systemd drop-in files, see systemd.unit(5).
11 |
12 | [Unit]
13 | Description=Automatically Unregister from Red Hat Insights
14 | Documentation=man:insights-client(8)
15 | After=network-online.target
16 | ConditionPathExists=!@sysconfdir@/pki/consumer/cert.pem
17 |
18 | [Service]
19 | Type=simple
20 | ExecStart=@bindir@/insights-client --unregister --force
21 | ExecStopPost=systemctl unmask --now insights-register.path
22 | ExecStopPost=systemctl start insights-register.path
23 | Restart=no
24 |
--------------------------------------------------------------------------------
/data/systemd/meson.build:
--------------------------------------------------------------------------------
1 | unit_sources = [
2 | 'insights-client-boot.service',
3 | 'insights-client.service',
4 | 'insights-client.timer',
5 | ]
6 |
7 | preset_sources = [
8 | '80-insights.preset'
9 | ]
10 |
11 | unit_inputs = [
12 | 'insights-client-results.service.in',
13 | 'insights-client-results.path.in'
14 | ]
15 |
16 | if get_option('auto_registration').enabled()
17 | unit_inputs += [
18 | 'insights-register.service.in',
19 | 'insights-register.path.in',
20 | 'insights-unregister.service.in',
21 | 'insights-unregister.path.in',
22 | ]
23 | preset_sources += '80-insights-register.preset'
24 | endif
25 |
26 | if get_option('checkin').enabled()
27 | unit_inputs += [
28 | 'insights-client-checkin.service.in'
29 | ]
30 | unit_sources += 'insights-client-checkin.timer'
31 | endif
32 |
33 | foreach unit_input : unit_inputs
34 | unit_sources += configure_file(
35 | input: unit_input,
36 | output: '@BASENAME@',
37 | configuration: config_data,
38 | )
39 | endforeach
40 |
41 | install_data(
42 | unit_sources,
43 | install_dir: systemd.get_pkgconfig_variable('systemdsystemunitdir')
44 | )
45 |
46 | install_data(
47 | preset_sources,
48 | install_dir: systemd.get_pkgconfig_variable('systemdsystempresetdir')
49 | )
50 |
--------------------------------------------------------------------------------
/data/tmpfiles.d/insights-client.conf:
--------------------------------------------------------------------------------
1 | R /var/tmp/insights-client* - - - 24h
2 |
--------------------------------------------------------------------------------
/data/tmpfiles.d/meson.build:
--------------------------------------------------------------------------------
1 | install_data(
2 | ['insights-client.conf'],
3 | install_dir: systemd.get_pkgconfig_variable('tmpfilesdir')
4 | )
5 |
--------------------------------------------------------------------------------
/docs/file-content-redaction.yaml.example:
--------------------------------------------------------------------------------
1 | ---
2 | # Omit lines from files and command output in the collection using parameters listed here.
3 |
4 | # Using YAML syntax, create lists of "patterns" and "keywords" to omit.
5 |
6 | # About the "patterns" section
7 | # ----------------------------
8 | # Lines matching the parameters specified will be omitted
9 | # in the order that the parameters are given, e.g.,
10 |
11 | # patterns:
12 | # - "example_string_1"
13 | # - "example_string_2"
14 |
15 | # Lines containing "example_string_1" or "example_string_2" will be
16 | # omitted from output.
17 |
18 | # Regular expression matching using egrep are available to use.
19 | # Wrap the list with "regex" like in the following example:
20 |
21 | # patterns:
22 | # regex:
23 | # - "abc.*"
24 | # - "localhost[[:digit:]]"
25 |
26 | # Lines matching these regular expressions will be omitted
27 | # from output.
28 |
29 | # NOTE: You cannot mix plain string matching and regular expression matching.
30 |
31 | # About the "keywords" section
32 | # ----------------------------
33 | # Replace the specified keywords with generic identifiers by the soscleaner module.
34 | # NOTE: In order to use keyword replacement, the "obfuscate" option must be enabled in
35 | # the insights-client.conf file.
36 |
37 | # Refer to https://access.redhat.com/articles/4511681 for up-to-date configuration information.
38 |
39 | # An example configuration is provided below.
40 |
41 | patterns:
42 | regex:
43 | - "abc.*"
44 |
45 | keywords:
46 | - "1.1.1.1"
47 | - "keyword_example"
48 |
49 | # More examples
50 | # --------
51 | # patterns:
52 | # regex:
53 | # # never send up lines with my host name suffix (example.com)
54 | # - "[a-zA-Z_.-]*example\.com"
55 | #
56 | # # never send up uncompressed IPv6 addresses
57 | # - "([0-9a-fA-F]{0,4}:){7}[0-9a-fA-F]{0,4}"
58 |
--------------------------------------------------------------------------------
/docs/file-redaction.yaml.example:
--------------------------------------------------------------------------------
1 | ---
2 | # Omit entire files and commands from the collection using parameters listed here.
3 |
4 | # Using YAML syntax, create lists of "components", "commands", and "files" to omit.
5 |
6 | # For a full list of files and commands run by insights-client,
7 | # refer to /etc/insights-client/.fallback.json
8 |
9 | # This file is deprecated and provided for compatibility only.
10 | # It will be removed in a future version.
11 |
12 | # Commands and files are provided here presently for compatibility only.
13 | # The use of components is preferred over commands and files, and any commands
14 | # or files that match components will be converted to components during parsing.
15 | # These commands and files must match entries in the .fallback.json file.
16 |
17 | # For a full list of Insights Core components, refer to the following:
18 | # https://insights-core.readthedocs.io/en/latest/specs_catalog.html
19 |
20 | # Components must be prefixed with "insights.specs.default.DefaultSpecs."
21 |
22 | # An example configuration is provided below.
23 |
24 | components:
25 | - insights.specs.default.DefaultSpecs.httpd_V
26 | - insights.specs.default.DefaultSpecs.mysql_log
27 | - insights.specs.default.DefaultSpecs.ifconfig
28 | commands:
29 | - /bin/rpm -qa
30 | - /bin/ls
31 | - ethtool_i
32 | files:
33 | - /etc/audit/auditd.conf
34 | - cluster_conf
35 |
--------------------------------------------------------------------------------
/docs/insights-client.8:
--------------------------------------------------------------------------------
1 | .\" insights-client - Red Hat Insights
2 | .TH "insights-client" "8" "" "Red Hat Insights" ""
3 | .SH "NAME"
4 | insights\-client \- Red Hat Insights Client tool
5 |
6 | .SH "SYNOPSIS"
7 | .B insights-client [options]
8 | .SH "DESCRIPTION"
9 | \fBinsights\-client\fP is designed to help customers proactively resolve issues affecting business operations in Red Hat Enterprise Linux and Red Hat Cloud Infrastructure environments. View alerts or learn more at https://console.redhat.com/insights/. Due to the dynamic nature of this application, some options may become available that are not described in the manual. Please refer to the output of --help for the most up-to-date options, or view https://access.redhat.com/articles/4099591 for more details.
10 |
11 |
12 | .SH "OPTIONS"
13 | .IP "-h, --help"
14 | Show this help message and exit.
15 | .IP "--register"
16 | Register host to the Red Hat Insights service.
17 | .IP "--unregister"
18 | Unregister host.
19 | .IP "--display-name=DISPLAYNAME"
20 | Display name to use for this host. May be used during registration.
21 | .IP "--group=GROUP"
22 | Add a tag name group with the specified value to this host. The tag will be saved to the tags file.
23 | .IP "--retry=RETRIES"
24 | Number of times to retry uploading. 180 seconds between tries.
25 | .IP "--validate"
26 | Validate the contents of the denylist configuration.
27 | .IP "--quiet"
28 | Only display error messages to stdout.
29 | .IP "--silent"
30 | Display no messages to stdout.
31 | .IP "--enable-schedule"
32 | Enable automatic scheduling.
33 | .IP "--disable-schedule"
34 | Disable automatic scheduling.
35 | .IP "--compressor"
36 | Specifies the compression algorithm to use. Choices are gz, bz2, xz, and none. Defaults to gz.
37 | .IP "--offline"
38 | Collect locally only, do not connect to Insights and do not upload.
39 | .IP "--payload=FILE"
40 | Skip collection and upload a specified archive. Requires --content-type.
41 | .IP "--content-type=TYPE"
42 | Content type of the archive specified with --payload.
43 | .IP "--diagnosis"
44 | Retrieve a diagnosis for this host.
45 | .IP "--compliance"
46 | Scan the system with OpenSCAP and upload the report.
47 | .IP "--check-results"
48 | Retrieve analysis results from the Red Hat Insights service.
49 | .IP "--show-results"
50 | Display analysis results from the Red Hat Insights service.
51 | .IP "--output-dir=DIR"
52 | Write the collection to a specified directory. Does not perform an upload.
53 | .IP "--output-file=FILE"
54 | Write the collection to a specified file. Does not perform an upload.
55 | .IP "--checkin"
56 | Perform a lightweight hourly check-in.
57 | .IP "--list-specs"
58 | Show insights-client collection specs.
59 | .IP "--compliance"
60 | Run a Compliance scan and upload.
61 | .IP "--module MODULE, -m MODULE"
62 | Run a module from within the insights.client package. Analogous to "python -m MODULE". Use only as directed.
63 |
64 | .SH "DEBUG OPTIONS"
65 | .IP "--version"
66 | Display version.
67 | .IP "--test-connection"
68 | Test connectivity to Red Hat.
69 | .IP "--verbose"
70 | DEBUG output to stdout
71 | .IP "--no-upload"
72 | Do not upload the archive.
73 | .IP "--keep-archive"
74 | Do not delete archive after upload.
75 | .IP "--support"
76 | Create a support logfile for Red Hat Insights.
77 | .IP "--status"
78 | Check this host's registration status by checking the presence of \fB/etc/insights-client/.registered\fP file.
79 | .IP "--net-debug"
80 | Log network activity to console.
81 |
82 | .SH "MOTD"
83 | A message will be displayed on login about \fBinsights\-client\fP if installed but has not yet been used at least once.
84 |
85 | To change this message, edit the \fB/etc/insights-client/insights-client.motd\fP file.
86 |
87 | To prevent this message to be shown on login, create the \fB/etc/motd.d/insights-client\fP symlink pointing to \fB/dev/null\fP.
88 |
89 | .SH "LOGGING"
90 | \fBinsights\-client\fP utilizes the 'logrotate' tool to rotate log files. To change log rotation options, edit the \fB/etc/logrotate.d/insights-client\fP file. Please refer to the 'logrotate' tool documentation to see all available configuration options.
91 |
92 | .SH "SEE ALSO"
93 | .BR insights-client.conf (5)
94 |
95 | \&
96 |
--------------------------------------------------------------------------------
/docs/insights-client.conf.5:
--------------------------------------------------------------------------------
1 | .\" insights-client.conf - Red Hat Insights
2 | .TH "insights-client.conf" "5" "" "Red Hat Insights Configuration" ""
3 | .SH "NAME"
4 | insights\-client.conf \- Red Hat Insights client configuration
5 |
6 | .SH "DESCRIPTION"
7 | The \fBinsights\-client.conf\fP file contains configuration information for \fBinsights\-client\fP, the client for the Red Hat Insights service. This file is in an INI style format, option=value, default or example values are shown below.
8 |
9 | [insights-client]\&
10 | .IP "loglevel=DEBUG"
11 | Change log level, valid options DEBUG, INFO, WARNING, ERROR, CRITICAL.
12 | .IP "auto_config=True"
13 | Automatically attempt to configure connectivity to Red Hat Insights. If an RHSM or Satellite subscription is detected, CERT auth will be automatically selected.
14 | .IP "base_url=cert-api.access.redhat.com:443/r/insights"
15 | Base URL for API Interactions.
16 | .IP "proxy=http://user:pass@192.168.100.50:8080"
17 | URL for the proxy.
18 | .IP "auto_update=True"
19 | Automatically update the dynamic configuration.
20 | .IP "obfuscate=False"
21 | Obfuscate IP addresses.
22 | .IP "obfuscate_hostname=False"
23 | Obfuscate hostname. Requires obfuscate=True.
24 | .IP "display_name="
25 | Display name for this system.
26 | .IP "ansible_host="
27 | Ansible hostname for this system.
28 | .IP "cmd_timeout=120"
29 | Timeout for commands run during collection, in seconds.
30 | .IP "http_timeout=120"
31 | Timeout for HTTP calls, in seconds.
32 | .IP "core_collect=True"
33 | Use Insights Core to perform the data collection when True. This option is provided for compatibility only and will be deprecated in a future release.
34 | .IP "redaction_file=/etc/insights-client/file-redaction.yaml"
35 | This file can be used to omit files or commands from the collection.
36 | .br
37 | See /usr/share/doc/insights-client/file-redaction.yaml.example or https://access.redhat.com/articles/4511681 for information on how to use it.
38 | .IP "content_redaction_file=/etc/insights-client/file-content-redaction.yaml"
39 | This file can be used to omit lines or keywords from files and commands in the collection.
40 | .br
41 | See /usr/share/doc/insights-client/file-content-redaction.yaml.example or https://access.redhat.com/articles/4511681 for information on how to use it.
42 | .IP "tags_file=/etc/insights-client/tags.yaml"
43 | Location of the tags file for this system.
44 | .SH "SEE ALSO"
45 | .BR insights-client (8)
46 | \&
47 |
--------------------------------------------------------------------------------
/docs/meson.build:
--------------------------------------------------------------------------------
1 | install_man(
2 | ['insights-client.8', 'insights-client.conf.5']
3 | )
4 |
5 | install_data(
6 | ['file-redaction.yaml.example', 'file-content-redaction.yaml.example'],
7 | install_dir: get_option('datadir') / 'doc' / meson.project_name()
8 | )
9 |
--------------------------------------------------------------------------------
/insights-client.spec:
--------------------------------------------------------------------------------
1 | %define _binaries_in_noarch_packages_terminate_build 0
2 |
3 | # This conditional build macro adds a "--with ros" commandline option to
4 | # rpmbuild. The default behavior is to build without it.
5 | %bcond_with ros
6 |
7 | Name: insights-client
8 | Summary: Uploads Insights information to Red Hat on a periodic basis
9 | Version: {{{ git_dir_version lead=3.2 }}}
10 | Release: 0%{?dist}
11 | Source: {{{ git_dir_pack }}}
12 | License: GPL-2.0-or-later
13 | URL: https://console.redhat.com/insights
14 | Group: Applications/System
15 | Vendor: Red Hat, Inc.
16 |
17 | BuildArch: noarch
18 |
19 | Requires: tar
20 | Requires: gpg
21 | Requires: pciutils
22 |
23 | %{?__python3:Requires: %{__python3}}
24 | %{?systemd_requires}
25 | Requires: python3-requests >= 2.6
26 | Requires: python3-PyYAML
27 | Requires: python3-six
28 | Requires: python3dist(setuptools)
29 | Requires: coreutils
30 |
31 | Requires: subscription-manager
32 |
33 | BuildRequires: wget
34 | BuildRequires: binutils
35 | BuildRequires: python3-devel
36 | BuildRequires: systemd
37 | BuildRequires: pam
38 | BuildRequires: meson
39 | BuildRequires: python3-pytest
40 | BuildRequires: systemd-rpm-macros
41 |
42 |
43 | %description
44 | Sends insightful information to Red Hat for automated analysis
45 |
46 | %if %{with ros}
47 | %package ros
48 | Requires: pcp-zeroconf
49 | Requires: insights-client
50 |
51 | Summary: The subpackage for Insights resource optimization service
52 |
53 | %description ros
54 |
55 | The ros subpackage add ros_collect configuration parameter to insights-client.conf file,
56 | the parameter is set to True by default. The system starts sending PCP archives to
57 | Resource Optimization service upon modifying ros_collect parameter to True.
58 | %endif
59 |
60 | %prep
61 | {{{ git_dir_setup_macro }}}
62 |
63 |
64 | %build
65 | %{meson} \
66 | -Dpython=%{__python3} \
67 | %if (0%{?rhel} && 0%{?rhel} < 10)
68 | -Dredhat_access_insights=true \
69 | %endif
70 | %{nil}
71 | %{meson_build}
72 |
73 |
74 | %install
75 | %{meson_install}
76 |
77 | # Create different insights directories in /var
78 | mkdir -p %{buildroot}%{_localstatedir}/log/insights-client/
79 | mkdir -p %{buildroot}%{_localstatedir}/lib/insights/
80 | mkdir -p %{buildroot}%{_localstatedir}/cache/insights/
81 | mkdir -p %{buildroot}%{_localstatedir}/cache/insights-client/
82 |
83 | %post
84 | %systemd_post %{name}.timer
85 | %systemd_post %{name}-boot.service
86 | if [ -d %{_sysconfdir}/motd.d ]; then
87 | if [ ! -e %{_sysconfdir}/motd.d/insights-client -a ! -L %{_sysconfdir}/motd.d/insights-client ]; then
88 | if [ -e %{_localstatedir}/lib/insights/newest.egg ]; then
89 | ln -sn /dev/null %{_sysconfdir}/motd.d/insights-client
90 | else
91 | ln -sn %{_sysconfdir}/insights-client/insights-client.motd %{_sysconfdir}/motd.d/insights-client
92 | fi
93 | fi
94 | fi
95 |
96 | %if %{with ros}
97 | %post ros
98 | rm -f /var/lib/pcp/config/pmlogger/config.ros
99 | sed -i "/PCP_LOG_DIR\/pmlogger\/ros/d" /etc/pcp/pmlogger/control.d/local
100 |
101 | if ! grep -q "^ros_collect" %{_sysconfdir}/insights-client/insights-client.conf; then
102 | cat <> %{_sysconfdir}/insights-client/insights-client.conf
103 | ### Begin insights-client-ros ###
104 | ros_collect=True
105 | ### End insights-client-ros ###
106 | EOF
107 | fi
108 | %endif
109 |
110 | %preun
111 | %systemd_preun %{name}.timer
112 | %systemd_preun %{name}.service
113 | %systemd_preun %{name}-boot.service
114 |
115 | %postun
116 | %systemd_postun %{name}.timer
117 | %systemd_postun %{name}.service
118 | %systemd_postun %{name}-boot.service
119 |
120 | # Clean up files created by insights-client that are unowned by the RPM
121 | if [ $1 -eq 0 ]; then
122 | rm -f %{_sysconfdir}/cron.daily/insights-client
123 | rm -f %{_sysconfdir}/ansible/facts.d/insights.fact
124 | rm -f %{_sysconfdir}/ansible/facts.d/insights_machine_id.fact
125 | rm -f %{_sysconfdir}/motd.d/insights-client
126 | rm -rf %{_localstatedir}/lib/insights
127 | rm -rf %{_localstatedir}/log/insights-client
128 | rm -f %{_sysconfdir}/insights-client/.*.etag
129 | fi
130 |
131 | %if %{with ros}
132 | %postun ros
133 | sed -i '/### Begin insights-client-ros ###/,/### End insights-client-ros ###/d;/ros_collect=True/d' %{_sysconfdir}/insights-client/insights-client.conf
134 | %endif
135 |
136 | %files
137 | %config(noreplace) %{_sysconfdir}/insights-client/*.conf
138 | %{_sysconfdir}/insights-client/insights-client.motd
139 | %{_sysconfdir}/insights-client/.exp.sed
140 | %{_sysconfdir}/insights-client/rpm.egg*
141 | %{_bindir}/*
142 | %{_unitdir}/*
143 | %attr(444,root,root) %{_sysconfdir}/insights-client/*.pem
144 | %attr(444,root,root) %{_sysconfdir}/insights-client/redhattools.pub.gpg
145 | %{python3_sitelib}/insights_client/
146 | %{_defaultdocdir}/%{name}
147 | %{_presetdir}/*.preset
148 | %attr(700,root,root) %dir %{_localstatedir}/log/insights-client/
149 | %attr(700,root,root) %dir %{_localstatedir}/cache/insights-client/
150 | %attr(750,root,root) %dir %{_localstatedir}/cache/insights/
151 | %attr(750,root,root) %dir %{_localstatedir}/lib/insights/
152 | %{_sysconfdir}/logrotate.d/insights-client
153 | %{_tmpfilesdir}/insights-client.conf
154 |
155 | %doc
156 | %defattr(-, root, root)
157 | %{_mandir}/man8/*.8.gz
158 | %{_mandir}/man5/*.5.gz
159 |
160 | %if %{with ros}
161 | %files ros
162 | %endif
163 |
164 | %changelog
165 | {{{ git_dir_changelog }}}
166 |
--------------------------------------------------------------------------------
/integration-tests/README.md:
--------------------------------------------------------------------------------
1 | # Running Betelgeuse
2 |
3 | ### Docs:
4 | https://betelgeuse.readthedocs.io/en/stable/
5 | https://betelgeuse.readthedocs.io/en/stable/config.html
6 |
7 | ## Test-case command
8 | Command generates an XML file suited to be imported by the **Test Case XML Importer**. It reads the Python test suite source code and generated XML file with all the information necessary.
9 |
10 | The `test-case` requires:
11 |
12 | - The path to the Python test suite source code
13 | - The Polarion project ID
14 | - The output XML file path (will be overwritten if exists)
15 |
16 |
17 | There should also be a custom config file specified for pythonpath for Betelgeuse to correctly read all the custom fields in the docstrings. The file is saved in integration-tests/custom_betelgeuse_config.py
18 |
19 | Example:
20 |
21 | ```console
22 | $ PYTHONPATH=integration-tests/ \
23 | betelgeuse --config-module \
24 | custom_betelgeuse_config test-case \
25 | integration-tests/ PROJECT ./test_case.xml
26 | ```
27 |
28 | This will create a test_case.xml file in integration-tests/
29 |
30 | ## Test-run command
31 | Command generates an XML file suited to be imported by the **Test Run XML Importer**.
32 |
33 | It takes:
34 |
35 | - A valid xUnit XML file
36 | - A Python test suite where test case IDs can be found
37 |
38 | And generates a resulting XML file with all the information necessary.
39 |
40 | It requires:
41 |
42 | - The path to the xUnit XML file
43 | - The path to the Python test suite source code
44 | - The Polarion user ID
45 | - The Polarion project ID
46 | - The output XML file path (will be overwritten if exists)
47 |
48 | It is also highly recommended to use `--response-property` as it will then be easier to monitor the importer messages
49 |
50 | Example:
51 |
52 | ```console
53 | $ PYTHONPATH=integration-tests/ \
54 | betelgeuse test-run \
55 | --response-property property_key=property_value \
56 | junit.xml \
57 | insights-client/integration-tests \
58 | testuser \
59 | betelgeuse-test-run.xml
60 | ```
61 |
62 | NOTE:
63 |
64 | `--dry-run` can be used with `test-run` command when testing the functionality.
--------------------------------------------------------------------------------
/integration-tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RedHatInsights/insights-client/cfe9826192b6369d61b4d20f91321795c8adb93a/integration-tests/__init__.py
--------------------------------------------------------------------------------
/integration-tests/conftest.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | import subprocess
3 | import time
4 | import logging
5 |
6 | logger = logging.getLogger(__name__)
7 |
8 |
9 | @pytest.fixture(scope="session")
10 | def install_katello_rpm(test_config):
11 | if "satellite" in test_config.environment:
12 | # install katello rpm before register system against Satellite
13 | satellite_hostname = test_config.get("candlepin", "host")
14 | cmd = [
15 | "rpm",
16 | "-Uvh",
17 | "http://%s/pub/katello-ca-consumer-latest.noarch.rpm" % satellite_hostname,
18 | ]
19 | subprocess.check_call(cmd)
20 | yield
21 | if "satellite" in test_config.environment:
22 | cmd = "rpm -qa 'katello-ca-consumer*' | xargs rpm -e"
23 | subprocess.check_call(cmd, shell=True)
24 |
25 |
26 | @pytest.fixture(scope="session")
27 | def register_subman(
28 | external_candlepin, install_katello_rpm, subman_session, test_config
29 | ):
30 | if "satellite" in test_config.environment:
31 | subman_session.register(
32 | activationkey=test_config.get("candlepin", "activation_keys"),
33 | org=test_config.get("candlepin", "org"),
34 | )
35 | else:
36 | subman_session.register(
37 | username=test_config.get("candlepin", "username"),
38 | password=test_config.get("candlepin", "password"),
39 | )
40 | yield subman_session
41 |
42 |
43 | def loop_until(predicate, poll_sec=5, timeout_sec=120):
44 | """
45 | An helper function to handle a time periond waiting for an external service
46 | to update its state.
47 |
48 | an example:
49 |
50 | assert loop_until(lambda: insights_client.is_registered)
51 |
52 | The loop function will retry to run predicate every 5secs
53 | until the total time exceeds timeout_sec.
54 | """
55 | start = time.time()
56 | ok = False
57 | while (not ok) and (time.time() - start < timeout_sec):
58 | time.sleep(poll_sec)
59 | ok = predicate()
60 | return ok
61 |
--------------------------------------------------------------------------------
/integration-tests/constants.py:
--------------------------------------------------------------------------------
1 | import pathlib
2 |
3 | HOST_DETAILS: str = "/var/lib/insights/host-details.json"
4 | REGISTERED_FILE: str = "/etc/insights-client/.registered"
5 | UNREGISTERED_FILE: str = "/etc/insights-client/.unregistered"
6 | MACHINE_ID_FILE: str = "/etc/insights-client/machine-id"
7 | TAGS_FILE = pathlib.Path("/etc/insights-client/tags.yaml")
8 |
--------------------------------------------------------------------------------
/integration-tests/custom_betelgeuse_config.py:
--------------------------------------------------------------------------------
1 | from betelgeuse import default_config
2 |
3 | TESTCASE_CUSTOM_FIELDS = default_config.TESTCASE_CUSTOM_FIELDS + (
4 | "casecomponent",
5 | "subsystemteam",
6 | "reference",
7 | "polarionincludeskipped",
8 | "polarionlookupmethod",
9 | "polarionprojectid",
10 | )
11 |
12 | DEFAULT_CASECOMPONENT_VALUE = ""
13 | DEFAULT_SUBSYSTEMTEAM_VALUE = ""
14 | DEFAULT_REFERENCE_VALUE = ""
15 | POLARION_INCLUDE_SKIPED = ""
16 | POLARION_LOOKUP_METHOD = ""
17 | POLARION_PROJECT_ID = ""
18 |
--------------------------------------------------------------------------------
/integration-tests/playbook_verifier/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RedHatInsights/insights-client/cfe9826192b6369d61b4d20f91321795c8adb93a/integration-tests/playbook_verifier/__init__.py
--------------------------------------------------------------------------------
/integration-tests/playbook_verifier/playbooks/README.md:
--------------------------------------------------------------------------------
1 | # Test data for the Ansible playbook verifier
2 |
3 | To verify the functionality of the verifier, these playbooks have been downloaded from git repository of config-manager:
4 | - [insights_setup.yml](https://github.com/RedHatInsights/config-manager/blob/master/playbooks/insights_setup.yml)
5 | - [compliance_openscap_setup.yml](https://github.com/RedHatInsights/config-manager/blob/master/playbooks/compliance_openscap_setup.yml)
6 |
7 | Additionally, this playbook has been downloaded from git repository of insights-ansible-playbook-verifier:
8 | - [bugs.yml](https://github.com/RedHatInsights/insights-ansible-playbook-verifier/blob/main/data/playbooks/bugs.yml)
9 |
10 | The list of playbooks should be extended to improve coverage:
11 | - lines ending with Windows-style line endings (`\r\n`),
12 | - comments with weird indentation,
13 | - playbook with comments stripped before verifying,
14 | - playbooks containing non-ASCII UTF-8 characters.
15 |
--------------------------------------------------------------------------------
/integration-tests/playbook_verifier/playbooks/bugs.yml:
--------------------------------------------------------------------------------
1 | # This testing file is used to identify, track, and fix issues. It allows adding
2 | # new issues as they are discovered and helps work through them step by step.
3 | - name: Set the LoginGraceTime with a regex and file mode to 0600
4 | hosts: localhost
5 | become: true
6 | vars:
7 | insights_signature_exclude: /hosts,/vars/insights_signature
8 | insights_signature: !!binary |
9 | TFMwdExTMUNSVWRKVGlCUVIxQWdVMGxIVGtGVVZWSkZMUzB0TFMwS1ZtVnljMmx2YmpvZ1IyNTFV
10 | RWNnZGpFS0NtbFJTV05DUVVGQ1EwRkJSMEpSU201b2NrOTNRVUZ2U2tWTmRuYzFPRVFyYWpWd1Rs
11 | SkJiMUF2TUhKVFowUmxWVU5DTDFoWFl6QlBkRW8xTTNabWJIb0tjWGhWWlRaNWRHcHZiVzkwZVhK
12 | alpHVjBhMmRyTjFseU9ITTJORVZKTnpsNVUxTndWVk40VTBncmIwWTJVMjkyU0RsSWFUQXJORWxK
13 | WlRWb1dsQjBRZ3BaUW05Q2FIUmpaRXRTWm1jMGVpOHJXRkYxT0ZOU1luVjZaak5FWTFRNWJVUjJk
14 | WGROTnprNGVHbFRjbTFZYTNGNVdUUmxkakZVYVZnM2RuRTNaREZGQ25GSGFtZGlOVTlDTUVJNE16
15 | bG5WM2xaYmtkV1NXNWtNV2xKUjB4UEwzSktaV3hqVHlzeWVFa3pVbGxQWnpRd1lVODRPR0pZZFZw
16 | cE1VeEllbXhJYm5FS2IydEZkWE5YU2l0VVEwbE9abUo2ZVN0QlIzZENWRXhCTWt4WVozSkZibmwz
17 | ZW5Fd2NteFNhMmhwTjI1c1luTTBkU3RoWlRGclNISnhPVTVLWkZGRFZncG1jRWxSU2k5eFdUSkxT
18 | MkYyWTJkUVEyWlNLMEZuZDJsalkwUmtlbEpDV2tWalEycHpWVzFDWlZNdlJrdFVSMFpHUlVneWJF
19 | SkRhRFpLWjNweFNsbHBDakZVU1c1cWF5dHlWamxuWkhkNk5uZGpWek5JZVhCdWVWZHFLMHBKTVda
20 | NWFUSnhaa0pKUVRoc1JWZHBiSFU1TTBWTVFXRXhhMHhpY1c5U2RWTmlUbThLWW1wM2RFOWpUSFZG
21 | VlZabllteHhlV2RpUldwRmNGRXJWMkpUZUdGMVptTnZVRzVWWTFGVWMzZFBZMmMwYVhCWlRUSTFN
22 | bWczZVZkSVRuaDBUa2hEYndwVVV6bE1NME5zVVVGcE9YTnRTMHRzWm1sVFNXc3JOMUJQZDJGT1dH
23 | SklObVZRTURobVltcFZWVkV6ZWpOQ1ZXa3lhMDFVZUdWQmVqWm9TbTE0UXk4ekNuQm1MMmRhYkVS
24 | eFprUk1jVXRHU0V4dVJra3lSa28yVGxGeVMwaFVOa2xVY21SelZ6WkxLM0ZIZFRWcmRWTmhlV04y
25 | YzBoeVMybEtPVmROWjNKSFRWSUtZVEpEZUdaQ1NHSllhbWhwZGtFNWVEbFZSMjE0ZGt0b1J5dG1j
26 | VVEyYmpCb1ozcElaM2swVWl0b01ESlRTbE40TkZwTldrNUZOVFZuVkhSdWExUnJNZ3BtT0Vsc1dH
27 | ZFZWbUZvV0VsS01HZ3pVa3QwYndvOVJXODBUd290TFMwdExVVk9SQ0JRUjFBZ1UwbEhUa0ZVVlZK
28 | RkxTMHRMUzBL
29 | tasks:
30 | - ticket: CCT-1065
31 | file:
32 | regexp: '(?i)^\s*LoginGraceTime'
33 | mode: 0600
34 |
35 | - name: Test string with quotes and special characters
36 | hosts: localhost
37 | become: true
38 | vars:
39 | insights_signature_exclude: /hosts,/vars/insights_signature
40 | insights_signature: !!binary |
41 | TFMwdExTMUNSVWRKVGlCUVIxQWdVMGxIVGtGVVZWSkZMUzB0TFMwS1ZtVnljMmx2YmpvZ1IyNTFV
42 | RWNnZGpFS0NtbFJTV05DUVVGQ1EwRkJSMEpSU201b2NsWlJRVUZ2U2tWTmRuYzFPRVFyYWpWd1Rp
43 | OW1iMUZCU25SWFZXRnFVRzlZTTFCQ1lubDJTMGxPSzFoV2EyNEtlQzlsUTJ0VWNHWlVWa2gwTTFa
44 | RVFubFVWVUZVUW01eU1sVTRNRVZxTHpSSUwxazJUemxXU25OVFZESmFTVUpxV1ZRNFdpOTVkSHBh
45 | TjBoSFMyWk9NZ3BzUzJ0TVJsSnpPRlIyVVdoaVFsRXdNbGt3TTNGa1lWWndaVU52ZGk5VGIwVXlh
46 | bnBoT0ZVMVkyZENNREZvTjJsYU4zWjNkVFZOUW5KcE9WTkhWRGQxQ25Od1VUZEpOQzlZUkRKRFQx
47 | Qk9WbVJ4WkNzNU5XUmlNSGxMV21kb2QySnphbnBLZURNM1JWbEhRa05XZUZOTmJuUnVTRzF6V0c1
48 | RVdsbHFlV0pIYmt3S1EwdFBkRkJCTDFoQ1NXOTVOMjF1VTI5aFVUUXdVVXg0WjJoU1RIaHRUMmxR
49 | WWxoRU1YUktRVGRGUzBaclZpODJPSGxIYW5FMWFHWnhNVVJEVDFjd013cFlOelJFWW14c1MwNU9T
50 | bEk1YUU4NGJEUk9TRVZDU210M2MwaHFUMHhhUjBwdVRYUjJSMmxRUmtFNE5HbExhV3g2T0RGbWVX
51 | cGFTbWd6UzJOTFRYVjRDbU41T0hZME9UWmxOaXRqV0ZWeGRGWkVPVWRPU2pacFFWWjBiSE4wTUc1
52 | VlpFSk1UM0pyVVhJMGVscDNNRnA1ZDJsblMyOWpSR2wyT1RocVptNTFWREVLYkhaNllYVXlZMnRO
53 | VTNSeFpYaEZaa1ZPU2psMWMyNXRhWGcwUVU1NVUxQlNlWGxvV0ZwdGVrWnZVMDV1YkhGbU5sRlhZ
54 | VVZ1YTIxaFJtNUtOVk5XS3dwTk1rSmlkSEV6ZHl0TlYyTmtaVWRvYVZkcGMyWXlNbXRwUkZKV01r
55 | ZFNSSEZ0UjBOTk1qUjBVRVZvVEhwNVNVeHhjbEpsZDJ4MVRVUm1Nbk0yUjA5TkNtMVNNRGxPT1Vs
56 | TFNYUm5ZMUpqUjBKaVdGTTJkMUp0TUdKa1UyaFNUMDV4TnpSUmMzZHJlRzAzYlcxd1JUaDZLMjVG
57 | UTNkWk1XNDBSbXRZYWxFM1lsVUtiVEE0VW1NMU1HczFRMWhCUTNkcVdqTlRXRzR3VWxaT1Qyc3JL
58 | M1pTU0VodlJFNTVkMUJpYUZkQlQzSndiak5CV1dweWFGWlpZbE4wWVU4clJDOTVjQXBvYUZsYWFV
59 | aHpOREZNWTBGSVNHZzBWRVowVVFvOVVqY3ZOQW90TFMwdExVVk9SQ0JRUjFBZ1UwbEhUa0ZVVlZK
60 | RkxTMHRMUzBL
61 | tasks:
62 | - ticket: CCT-1065
63 | value: >
64 | This_string_contains_special_characters,
65 | single'quote, double"quote, both'"quotes,
66 | backslashes\\need to be\\\\escaped!\\
67 | Newlines?\nYep, they stay.
68 | Tabs\t too!
69 | ~End~
70 |
71 | - name: Test a play with an empty map
72 | hosts: localhost
73 | become: true
74 | vars:
75 | insights_signature_exclude: /hosts,/vars/insights_signature
76 | insights_signature: !!binary |
77 | TFMwdExTMUNSVWRKVGlCUVIxQWdVMGxIVGtGVVZWSkZMUzB0TFMwS1ZtVnljMmx2YmpvZ1IyNTFV
78 | RWNnZGpFS0NtbFJTV05DUVVGQ1EwRkJSMEpSU201b2NsWldRVUZ2U2tWTmRuYzFPRVFyYWpWd1Ru
79 | cDJaMUZCU2xwR1p6VlBRVUZRU1haSU1XdG5jblJIWWtkM2VFb0taelJTWmk4NGVpODNhV1JOTHpJ
80 | MFREQTRla2RqVWxCMlVFeDBaRFYxYzI4NU5qaElTa3hEVlhoV2NVMTZaRUZEVUVkV2RqWlBWV0pC
81 | WWxCUFRsUlJjZ3B0WjNKUEwzTjRUblkzVUhKQ1IzWjRMMjAyYUhSVlprd3lVWFJCU1VaeUswOHpO
82 | Vk5CTVhaNGF5OUpNMlJJTlVGMU9XVXZNbFExWjBGWWVFdHZRWG96Q2tsd01GVkxOakZKV25WcGRu
83 | Z3JaV1oxVUhSR2JqQmlkQ3ROZDA5VlJXMVFkUzlsVTJWUVIycFZhSHBRTjJKU1JWaE9LMmR1TlRR
84 | elZHYzFRMEZqZFRRS09WbDBTV1UyVW5kTU5UaEpUR3hHWms5d01FUkJaMHRoYTFSSFNtYzBSWEIy
85 | YVRCVWVVbHViRTVYYTNoTVEyOWtMM0FyUVdOd01Wb3hUVTVhWlhWaEx3cEZZbVpsTUVwUU5qWTJi
86 | VU5SUjBWVFVHbHlUV2xTZW5GNU1sQXplVTh3ZG5ScGVteDNlRkp5UWtVNFIwOVZZMVpxYkhKUGMz
87 | bEdUM1ZqY0ZNM1IwZHRDbnBLUnpoRFRWbGFSM2hSYVc1VVFuUXZSRmRqU1VReGJrZGxhMGxFYkda
88 | VmNuSmxXV0ZzV2xCRlkwNDVlVkF6TTNWNEszbGtZVWg2VDNGSU9ITnNlbEFLZUUxRmRITnJVa3BM
89 | Um5WVFFYRkZiRGdyV0hGV1kyTnBaM2RGVm14VmEyWlFiR3RDUkZJNFdIRlJibHB6ZHpsSk1WcFdV
90 | MHg2T1V0UlFuVkJORTV6VHdwRVVXRlhNVXRTYTFsaWVHb3liRUp2YkZCeFJpOU5NRzVOVEVZeksx
91 | ZHdVRUpUUkRONVQzZzJLeko0VWpGd1JuSXdTVVpGTmxWMVUwbFhWMHMyVVVwQ0NqWTNhWE12TUNz
92 | eFZYcEpjMUY0U2tKbVZXTXdiVkprYzNSS1VFdG5WMHQzWjIxR1QyYzVWRXBFSzFkeVV6ZGtNV2M1
93 | U1RCWE1VSjRPV3hzVFhGbVVYY0tjekF6VW5RMGFsZHdaUzlPWTJ3NVNHZHJkMG95Y1M4MWVXaHpV
94 | bTk1ZFVOR1ZUaDZlbkJWVXpKaFYyUlRkR2h3WnpWMlZHUnRaeXRXYlZSNlpqVlNPUXBLYTJrek5I
95 | WlpTa1puZDIxbGNsZFphVlU0TlFvOWVteDFWd290TFMwdExVVk9SQ0JRUjFBZ1UwbEhUa0ZVVlZK
96 | RkxTMHRMUzBL
97 | tasks:
98 | - ticket: CCT-1101
99 | value: {}
100 |
101 | - name: Test a play with an empty value
102 | hosts: localhost
103 | become: true
104 | vars:
105 | insights_signature_exclude: /hosts,/vars/insights_signature
106 | insights_signature: !!binary |
107 | TFMwdExTMUNSVWRKVGlCUVIxQWdVMGxIVGtGVVZWSkZMUzB0TFMwS1ZtVnljMmx2YmpvZ1IyNTFV
108 | RWNnZGpFS0NtbFJTV05DUVVGQ1EwRkJSMEpSU201b2NsWmhRVUZ2U2tWTmRuYzFPRVFyYWpWd1Rs
109 | RnRhMUZCU1VGSFlqSmtSWE5NYkVKdlNrRm5Oa3hHUjB0VGRWWUtXRmhrSzBGcFJrYzBiSFJOV1cx
110 | RU5tc3dTRmxTUjJkUk9WRXpiREp2VUhoelRqRTFjVzl0TkV4SmJsazRZVkZxYjNGR1N6Vm9UV2N2
111 | WXpGcWQwdDFTZ3BsUkdFNGNYcFBURFZ4VjNFeVlXcGFlak0wU1d4aFRrMUVZM2xLTm00MVltbFhU
112 | bHBqZWs0eWEwcHNUaTlJWlV4cGJtSjFiSEJSWnpBMVpYSkxjWFJNQ2xWcFRGbDZkR0pGVGxsQ05r
113 | dFFWSGhJUjB0R1kzRkVka05hVjBaUWExRm1lVmhOZDNNeVFXeGpSbGRzYVhGcFdWWm9MelJRV1Vv
114 | NU1IaG1RbVpoWkdjS09EUlFiMFF5WmtkemRtNUdTVGgyTkhsWEwxbFRUV1p4VmpoMmVsUm9hV3RM
115 | VUdWb1kzcFZRazlNUVdKdVVWUmFObkZ4Y1dSU09YTlpNR2xtZHpSc1lRcGpjRWhrWTNnd1VsRkhM
116 | MDR3ZHpGUGVHbHphRkZKYXpSd1FYUk1NRXhZUkVwdk5IRklUWEptVTJsTmIwUjVNMVJxV1N0NlZX
117 | OTZPVUpHV1RWalJHZHJDblJtZVdSRFEyNVFRMnRVYjI1SGNFZDJla3BVTms5d1J6bHJkRTFaTjBj
118 | NFYxZHdOazh4ZGxwMldUUlRaVU5WVFdkNWJtWnlhbEo0VDBGcUsxZ3haV29LUzBsMlVXUXpaa2xM
119 | ZDJWSFNtWjNOamxsVTJWbWNGUkVlblIyUlhKM01IZEhNekUyUm1nMWNGRXdWSEJZYlhsV1ZVVmtN
120 | MlVyYTFGaE1tZzBPVWxvYkFwaWNXdGliV1JHYjFoSVIwSTNXWFE1VlVocVZrWmtabGxqV2k5MlpX
121 | TmFVR2wzV25aa1FYSnpTRTg0V0VweFNqUndUV2xpZEVsaE5GZEVOVnBKVldkMkNtWjFSbHAyZVRK
122 | NlJqWk5XWEJQY3pSRlpraGphbUo2TlRkWlVFVllUMGxpWkZVemQyeHdibEZxUVhVeVZXOXBVbFJP
123 | UnpabVdHMUxVbTlyVjFWMVJIZ0tjME52ZW05amVYbHJZMU5xTTJKNU9YWnhjVTVtUzNsVWRURjVR
124 | WFptYVdscWMzUnFia3hwV1RsM2JGYzRLMmRZWWxwdmNXeEtSRVEzWmsxeldFOHdOZ3BCYnpWV1ZF
125 | a3lNVWhhZUUxSVdtZHJLMUpyU1FvOWJHVk5RZ290TFMwdExVVk9SQ0JRUjFBZ1UwbEhUa0ZVVlZK
126 | RkxTMHRMUzBL
127 | tasks:
128 | - ticket: CCT-1102
129 | value:
130 |
--------------------------------------------------------------------------------
/integration-tests/playbook_verifier/playbooks/compliance_openscap_setup.yml:
--------------------------------------------------------------------------------
1 | # This playbook will install the required OpenSCAP packages to get your systems ready to be used
2 | # with Insights Compliance service.
3 | #
4 | # After running this playbook, perform the following steps manually:
5 | # 1. Create a Compliance policy in cloud.redhat.com and associate the required systems.
6 | # 2. Run `insights-client --compliance` on your system to report Compliance to cloud.redhat.com
7 |
8 | - name: Compliance OpenSCAP Setup
9 | hosts: localhost
10 | become: yes
11 | vars:
12 | insights_signature_exclude: /hosts,/vars/insights_signature
13 | insights_signature: !!binary |
14 | TFMwdExTMUNSVWRKVGlCUVIxQWdVMGxIVGtGVVZWSkZMUzB0TFMwS1ZtVnljMmx2YmpvZ1IyNTFV
15 | RWNnZGpFS0NtbFJTVlpCZDFWQldUbE1WREpqZG5jMU9FUXJhalZ3VGtGUmFIaDFRa0ZCWjA1cE9D
16 | OXJTVFZQYW5reWMySjJOR3BXWlVKdEx6WnZiR3RpTlV4SVVrRUtiRzVtY2tOSFp6Sm5NVEZoYUU1
17 | TEx6RmpkVzVPUWsxTmVUazFXV3RKTlU1cWRtNXpOVVpHVTNSTFowMHdWV0Z3YjFoaVZWQktSV1pT
18 | U2xWRUwzUXhaUXBJVURaUlEwTldTa1l5VFVWWldIcHZVVzFsTUVSc01FeERaMUlyU1hvd2NWaFJa
19 | R2t2WVRSWWNEVnBWRkZTVW5OT1l5OXBWa2cxZFZZemVscHNNbWN4Q2xsRE1sQlFOVzkyZDBwMGFU
20 | RlFjemRyYmtabmJIcERiVWxPVUdGdllYVlRTamhoUkU5a00wSkxZbXRTVW10cmVXNDJORlJzVWtn
21 | eE9HSXdSbGh0Y1VrS2VHaE5hMVZRVEhOd1UwVkxZWGhqTDA5UVNUUXJPVEkwSzI0NVRHRnlUWFZO
22 | THpncmVURlNTa1pTT1hNMk5GaFVaMmh6VEdkQ2JtNXlPRE41VTFKWmJ3cHVWelpDY0c0eVowdzNR
23 | MHBCVHpabmJsZFhZbUphZURVNVdYRTRkV2RpYldWTFJFUXJSalZqVmpSaFpFaENXV3BZUmpkbFRY
24 | bEpUbTlvUzA5WVNtUkRDbkpzU1VSUlJUUktSM2RGU1dJMmRHSnNVWEJMYVhZeFFWZzNNbFF4WjFS
25 | WFNVUXdPVEZEVEU1Rk0wZERVa2M0VnpWeVl6SkRTVkJRYW5KNlNUWldTVWdLTWpVclltbEVPVTFp
26 | YW5sSFVXNVZRMkV3SzBGVlZsVlVibmxYVUhWRFEyeHhlbWhHYXpsVGRYQjRlRXh2VDBkTkwxTnlj
27 | elp2UlZFMFptUk1RV3BKYVFwd1ptUkdRVkI0VEdJMmNGVldSRkJGTVZFeU5GWXZXamd6WkZwTll5
28 | dHhORVJzZWtKV09EaHFaMDlwVWxOc1lYSktTQzl2YUZkSGNVSjFZM1oxYjBZMkNqQTRNamxLYVhW
29 | ak5rOHlUa1ZOYTNjNU1YUjVaSEJPZG1kbU5HNVhhbmRPYmt0Q1ZsTkViR3gyTW01QlQwcHdaRVZx
30 | WVhoRFl5c3hVVkJTU1cxWk5WTUtPRTFQUjBjMlRuRmxWMDV1VGtwaVYzRTBXRVp3Y2xOSlJFZHJV
31 | MFpFVmxkQllURlNka3RyYVV4bVMxQTFlQzh4V2pkT2RITTVWbGhVU0VwQ09YbHVad3BoYUdJeFFs
32 | aHhaM3B2VFQwS1BVTkphbWtLTFMwdExTMUZUa1FnVUVkUUlGTkpSMDVCVkZWU1JTMHRMUzB0Q2c9
33 | PQ==
34 | tasks:
35 | - name: Install OpenSCAP packages for Compliance service
36 | ansible.builtin.package:
37 | name:
38 | - openscap
39 | - openscap-scanner
40 | - scap-security-guide
41 | state: latest
42 | when:
43 | - ansible_facts.ansible_cmdline.ostree is undefined
--------------------------------------------------------------------------------
/integration-tests/playbook_verifier/playbooks/insights_setup.yml:
--------------------------------------------------------------------------------
1 | # Steps required to get your system ready to use the Insights Client:
2 | # 1. Yum install the insights-client
3 | # 2. Register the insights-client
4 | # 3. Modify file permissions
5 | - name: Insights Setup
6 | hosts: localhost
7 | become: yes
8 | vars:
9 | insights_signature_exclude: /hosts,/vars/insights_signature
10 | insights_signature: !!binary |
11 | TFMwdExTMUNSVWRKVGlCUVIxQWdVMGxIVGtGVVZWSkZMUzB0TFMwS1ZtVnljMmx2YmpvZ1IyNTFV
12 | RWNnZGpFS0NtbFJTVlpCZDFWQldUbG1jbHBqZG5jMU9FUXJhalZ3VGtGUmFrWjFaeTh2WTJJMWMw
13 | MVJkWEpPZG5oM05rMTRSVXRtUW1OU1MxbzBNVzVPUzBkRlFYQUtaVTh2VkZka00ySlVZVVZQYjBK
14 | bUx6RXpiVlUyUVRGWlJYQlJaM3BFTWtwMWFqVlNWWEJVT0RSdWJHazNMMWRMVDFwMmJURjRWR28w
15 | YTNWRWVXSlROQXB6TUZBd1pWRnBXR1V3ZUVwQmFVeDRRVkJ2Y25KRVlsbFNWR0Y2YVRNemJucENS
16 | bkIyVVVoMmEybG9hRFpVYkM5TWNITjZURXREZDNSSFZVWk5kazVxQ21wVFRGbFJXV0o1YlZWVFZ6
17 | RnBXR0ZyTW5SSU9FbEtaVTU2VFRWSmJFTm5TM1UzYVRsdVVUYzFORWswV0hFeFFUbEpOMGRJVG1J
18 | MU1WaFpkRTVyWm5vS1EwdzNRVk0zVHpCcGEwaGhZblJxSzJWdGIyWlhjVkJ4VVdwamRsUlZNa1Ey
19 | YldaMk1YRnNXRWhITjBSaU4zTmxWRk5hUW1oS1JuUkhOVk51Um5oMU1ncHJiMFZrVjJoV1dYZFNN
20 | MDlZWmtoWVRXcEdjVTEzWlROT2NuaHhaR2d6VWpRMlJ6Tk5WVk5zZGtSVlIwdzFUVzFqYWsweFNt
21 | TnZVSHBWWkdnMmRFeFdDbXhWZEhKVlJuVmxkbkJNYmxad1NFczRUemhWU0VOdGVHNTRNSGhQWTFW
22 | Wk5XZHlVMmhOYTAwMVlUVkhRa0ZvVVdOYU9FNXVZME5ETmpGTVNsRnFhM2NLUW1Vck1sVlhlSFZ6
23 | TW1sclFsUjJWeTlDYUVsRlRFTmtORUZSYmxGdFYxRXJkVmhTVUdJd2RHTkNVMVZDVlVOTVNERmpS
24 | VTgyWjFoWGNrUlRUbWxUTWdwd2VHdDNURnBKYlRSbGN6TXdVbWd3V0ZCeFZUVm1iazE0YTFaTlFX
25 | VmhOVlV4V0ZwdFkwUnpNeTlaUVRCNmFFbEJaRVJET0doelMxTkVURkJJUmtKdUNtVmxNRVJXUkdk
26 | SksycFVaUzlSUkhkMk0yMWpiRk0yWVUxMmFYVlJaa05uWjJkV1ZtOXFURTVJU2paNGVtNVZjMFl4
27 | WVRoVVZ6YzNkMlJyYkdkcWNrc0tPVlV5V0VabFJISm9iWFpxZGxWcmFXY3JlbEJLYTBwYWNXUmtk
28 | MHBVZEV4UWMwbGlOMFpFYjB0UFIwSXJiR3BSY1RkMFlURTBUR2R2YURZck1IaGxVd292VFZsb056
29 | WlRUWEp4UlQwS1BXZ3JOMEVLTFMwdExTMUZUa1FnVUVkUUlGTkpSMDVCVkZWU1JTMHRMUzB0Q2c9
30 | PQ==
31 | tasks:
32 | - name: Install latest insights-client, rhc, rhc-worker-playbook
33 | ansible.builtin.package:
34 | name:
35 | - insights-client
36 | - rhc
37 | - rhc-worker-playbook
38 | state: latest
39 | when:
40 | - ansible_facts.ansible_cmdline.ostree is undefined
41 |
42 | # With legacy_upload=True: Insights API says this machine is NOT registered.
43 | # With legacy_upload=False: This host is unregistered.
44 | - name: Get insights-client's status
45 | command: insights-client --status
46 | changed_when: false
47 | failed_when: false
48 | register: result
49 | - name: Register insights-client
50 | command: insights-client --register
51 | when: '"NOT registered" in result.stdout or "unregistered" in result.stdout'
52 |
53 | # insights_remove.yml stops and disables insights-client.timer, but leaves host registered.
54 | - name: Schedule insights-client runs
55 | command: insights-client --enable-schedule
--------------------------------------------------------------------------------
/integration-tests/playbook_verifier/test_verifier.py:
--------------------------------------------------------------------------------
1 | """
2 | :casecomponent: insights-client
3 | :requirement: RHSS-291297
4 | :polarion-project-id: RHELSS
5 | :polarion-include-skipped: false
6 | :polarion-lookup-method: id
7 | :subsystemteam: rhel-sst-csi-client-tools
8 | :caseautomation: Automated
9 | :upstream: Yes
10 | """
11 |
12 | import pathlib
13 | import subprocess
14 | import sys
15 | import pytest
16 | from pytest_client_tools.util import Version
17 |
18 |
19 | PLAYBOOK_DIRECTORY = pathlib.Path(__file__).parent.absolute() / "playbooks"
20 |
21 |
22 | @pytest.mark.parametrize(
23 | "filename",
24 | [
25 | "insights_setup.yml",
26 | "compliance_openscap_setup.yml",
27 | "bugs.yml",
28 | ],
29 | )
30 | @pytest.mark.tier1
31 | def test_official_playbook(insights_client, filename: str):
32 | """
33 | :id: 3659e27f-3621-4591-b1c4-b5f0a277bb72
34 | :title: Test playbook verifier
35 | :parametrized: yes
36 | :description:
37 | This test verifies the official playbooks against the GPG key
38 | the application ships.
39 | :tags: Tier 1
40 | :steps:
41 | 1. Read playbook file content
42 | 2. Run insights-client verifier with playbook
43 | 3. Compare output to input
44 | :expectedresults:
45 | 1. File content is correctly read and loaded into memory
46 | 2. Subprocess executes successfully without errors
47 | 3. Verifier's output matches original playbook content
48 | """
49 | if (
50 | sys.version_info >= (3, 12)
51 | and insights_client.core_version < Version(3, 5, 2)
52 | and filename == "bugs.yml"
53 | ):
54 | pytest.xfail(
55 | f"Core {insights_client.core_version} suffers from "
56 | "CCT-1065, CCT-1101, CCT-1102."
57 | )
58 |
59 | playbook_content: str = (PLAYBOOK_DIRECTORY / filename).read_text()
60 |
61 | result = subprocess.run(
62 | [
63 | "insights-client",
64 | "-m",
65 | "insights.client.apps.ansible.playbook_verifier",
66 | "--quiet",
67 | "--payload",
68 | "noop",
69 | "--content-type",
70 | "noop",
71 | ],
72 | input=playbook_content,
73 | stdout=subprocess.PIPE,
74 | stderr=subprocess.PIPE,
75 | universal_newlines=True,
76 | check=True,
77 | )
78 |
79 | # The playbooks may and may not include newline as EOF.
80 | assert result.stdout.strip() == playbook_content.strip()
81 |
--------------------------------------------------------------------------------
/integration-tests/requirements.txt:
--------------------------------------------------------------------------------
1 | git+https://github.com/RedHatInsights/pytest-client-tools@main
2 | pyyaml
3 | pytest-subtests
4 | distro
5 |
--------------------------------------------------------------------------------
/integration-tests/test_checkin.py:
--------------------------------------------------------------------------------
1 | """
2 | :casecomponent: insights-client
3 | :requirement: RHSS-291297
4 | :polarion-project-id: RHELSS
5 | :polarion-include-skipped: false
6 | :polarion-lookup-method: id
7 | :subsystemteam: rhel-sst-csi-client-tools
8 | :caseautomation: Automated
9 | :upstream: Yes
10 | """
11 |
12 | import contextlib
13 | import json
14 | import pytest
15 | from pytest_client_tools.util import Version
16 |
17 | from constants import HOST_DETAILS
18 | import conftest
19 |
20 | pytestmark = pytest.mark.usefixtures("register_subman")
21 |
22 |
23 | @pytest.mark.tier2
24 | def test_ultralight_checkin(insights_client, test_config):
25 | """
26 | :id: c662fd5e-0751-45e4-8477-6b0d27f735ac
27 | :title: Test lightweight check-in updates staleness timestamps
28 | :description:
29 | This test verifies that performing an ultra-light check-in with the
30 | insights-client updates the host's 'stale_timestamps' and 'updated'
31 | fields on the server
32 | :tags: Tier 2
33 | :steps:
34 | 1. Register the insights-client
35 | 2. Run '--check-results' and record the 'stale_timestamp' and 'updated'
36 | timestamps before check-in
37 | 3. Perform an ultra-light check-in ny running '--checkin'
38 | 4. Run '--check-results' and record the 'stale_timestamp' and 'updated'
39 | timestamps again
40 | 5. Verify that timestamps were updated successfully
41 | :expectedresults:
42 | 1. Insights-client is registered
43 | 2. The initial timestamps were retrieved and recorded
44 | 3. The check-in completes without any errors
45 | 4. The updated timestamps were retrieved and recorded
46 | 5. Both updated timestamps will be greater than before check-in
47 | """
48 | insights_client.register()
49 | assert conftest.loop_until(lambda: insights_client.is_registered)
50 |
51 | # Performing check-results operation provides latest host data in host-details.json
52 | insights_client.run("--check-results")
53 | with open(HOST_DETAILS, "r") as data_file:
54 | data = json.load(data_file)
55 | stale_ts_before_checkin = data["results"][0]["stale_timestamp"]
56 | updated_ts_before_checkin = data["results"][0]["updated"]
57 |
58 | # Performing an ultra light check-in
59 | insights_client.run("--checkin")
60 | insights_client.run("--check-results")
61 |
62 | with open(HOST_DETAILS, "r") as data_file:
63 | data = json.load(data_file)
64 | stale_ts_after_checkin = data["results"][0]["stale_timestamp"]
65 | updated_ts_after_checkin = data["results"][0]["updated"]
66 |
67 | assert stale_ts_after_checkin > stale_ts_before_checkin
68 | assert updated_ts_after_checkin > updated_ts_before_checkin
69 |
70 |
71 | @pytest.mark.tier1
72 | def test_client_checkin_unregistered(insights_client):
73 | """
74 | :id: 91331995-20c2-4d44-8abe-74a3e7d28309
75 | :title: Test check-in fails for unregistered client
76 | :description:
77 | This test verifies that attempting to perform check-in while unregistered
78 | fails with appropriate error message
79 | :tags: Tier 1
80 | :steps:
81 | 1. Unregister the insights-client if registered
82 | 2. Attempt to perform a check-in by running '--checkin'
83 | :expectedresults:
84 | 1. Insights-client is unregistered successfully
85 | 2. The check-in fails with return code 1 and message 'Error: failed
86 | to find host with matching machine-id'
87 | """
88 | with contextlib.suppress(Exception):
89 | insights_client.unregister()
90 | assert conftest.loop_until(lambda: not insights_client.is_registered)
91 |
92 | checkin_result = insights_client.run("--checkin", check=False)
93 | if insights_client.core_version >= Version(3, 4, 25):
94 | assert checkin_result.returncode > 0
95 | assert "This host is not registered" in checkin_result.stdout
96 | else:
97 | assert checkin_result.returncode == 1
98 | assert (
99 | "Error: failed to find host with matching machine-id"
100 | in checkin_result.stdout
101 | )
102 |
--------------------------------------------------------------------------------
/integration-tests/test_client.py:
--------------------------------------------------------------------------------
1 | """
2 | :casecomponent: insights-client
3 | :requirement: RHSS-291297
4 | :polarion-project-id: RHELSS
5 | :polarion-include-skipped: false
6 | :polarion-lookup-method: id
7 | :subsystemteam: rhel-sst-csi-client-tools
8 | :caseautomation: Automated
9 | :upstream: Yes
10 | """
11 |
12 | import contextlib
13 | import glob
14 | import os
15 | import subprocess
16 | import pytest
17 | import conftest
18 |
19 |
20 | @pytest.mark.usefixtures("register_subman")
21 | @pytest.mark.tier1
22 | def test_client_files_permission(insights_client):
23 | """
24 | :id: e793cf5e-1c25-4e31-93c9-6f0465f50cae
25 | :title: Verify client files permission
26 | :description:
27 | Verify that the permission for the last upload file
28 | /etc/insights-client/.lastupload is set to 0644
29 | :reference: https://bugzilla.redhat.com/show_bug.cgi?id=1924990
30 | :tags: Tier 1
31 | :steps:
32 | 1. Remove /etc/insights-client/.lastupload if it exists
33 | 2. Register insights-client
34 | 3. Verify the file permissions
35 | :expectedresults:
36 | 1. The file /etc/insights-client/.lastupload does not exist
37 | 2. The insights-client is registered
38 | 3. The permission of /etc/insights-client/.lastupload is set to 0644
39 | """
40 | file_last_upload = "/etc/insights-client/.lastupload"
41 | with contextlib.suppress(FileNotFoundError):
42 | os.remove(file_last_upload) # performing a cleanup before test
43 | insights_client.register()
44 | assert conftest.loop_until(lambda: insights_client.is_registered)
45 | assert oct(os.stat(file_last_upload).st_mode & 0o777) == "0o644"
46 |
47 |
48 | @pytest.fixture()
49 | def rpm_ql_insights_client():
50 | cmd = ["rpm", "-ql", "insights-client"]
51 | list_file = subprocess.check_output(cmd, universal_newlines=True)
52 | return list_file.split("\n")
53 |
54 |
55 | @pytest.mark.parametrize(
56 | "filename",
57 | [
58 | "/etc/insights-client/insights-client.motd",
59 | "/etc/insights-client/insights-client.conf",
60 | "/usr/lib/systemd/system/insights-client-boot.service",
61 | "/usr/lib/systemd/system/insights-client-results.path",
62 | "/usr/lib/systemd/system/insights-client-results.service",
63 | "/usr/lib/systemd/system/insights-client.service",
64 | "/usr/lib/systemd/system/insights-client.timer",
65 | "/usr/share/doc/insights-client/file-content-redaction.yaml.example",
66 | "/usr/share/doc/insights-client/file-redaction.yaml.example",
67 | "/usr/share/man/man5/insights-client.conf.5.gz",
68 | "/usr/share/man/man8/insights-client.8.gz",
69 | "/etc/logrotate.d/insights-client",
70 | ],
71 | )
72 | @pytest.mark.tier1
73 | def test_client_rpm_mandatory_files(filename, rpm_ql_insights_client):
74 | """
75 | :id: c7d2edbe-ae78-47e0-9b3d-ae1634c0ac79
76 | :title: Verify mandatory files for RPM
77 | :parametrized: yes
78 | :description: Verify the existence of mandatory files for the insights-client RPM
79 | :tags: Tier 1
80 | :steps:
81 | 1. List all files in the insights-client RPM package
82 | 2. Check if each mandatory file exists in the package
83 | :expectedresults:
84 | 1. A list of files is generated
85 | 2. All of the mandatory files are present in the RPM
86 | """
87 | assert (
88 | filename in rpm_ql_insights_client
89 | ), f"{filename} is not in insights-client package"
90 |
91 |
92 | @pytest.mark.usefixtures("register_subman")
93 | @pytest.mark.tier1
94 | def test_client_logfiles_mask(insights_client):
95 | """
96 | :id: 8f24500c-d0ff-4ab1-a2ae-3b99cbf68e36
97 | :title: Verify client logfiles permissions
98 | :description:
99 | Verify that the log files in
100 | /var/log/insights-client have the correct mode 0600
101 | :reference: https://bugzilla.redhat.com/show_bug.cgi?id=1955724
102 | :tags: Tier 1
103 | :steps:
104 | 1. Register insights-client
105 | 2. Check the file permission of each log file generated
106 | :expectedresults:
107 | 1. Insights-client is registered
108 | 2. The file permissions for all log files are 0600
109 | """
110 | # It is necessary to perform some command using insights-client
111 | # to populate logs
112 | insights_client.register()
113 | logfiles = glob.glob("/var/log/insights-client/*.log*")
114 | for logfile in logfiles:
115 | assert oct(os.stat(logfile).st_mode & 0o777) == "0o600"
116 |
117 |
118 | @pytest.mark.tier1
119 | def test_client_logdir_permissions():
120 | """
121 | :id: 204b1d54-6d8f-4d87-9227-cf3924cc5bb8
122 | :title: Verify log directory permissions
123 | :description:
124 | Verify that the permissions on the directory
125 | /var/log/insights-client are set to 0700
126 | :tags: Tier 1
127 | :steps: Check the directory permissions of /var/log/insights-client
128 | :expectedresults: The directory permissions are set to 0700
129 | """
130 | logdir_name = "/var/log/insights-client"
131 | assert oct(os.stat(logdir_name).st_mode & 0o777) == "0o700"
132 |
133 |
134 | @pytest.mark.usefixtures("register_subman")
135 | @pytest.mark.tier1
136 | def test_verify_logrotate_feature(insights_client):
137 | """
138 | :id: 5442729f-c6bc-4322-aa17-facd538e9fc3
139 | :title: Verify Logrotate feature
140 | :description: Verify that the logrotate works properly for insights-client
141 | :reference: https://bugzilla.redhat.com/show_bug.cgi?id=1940267
142 | :tags: Tier 1
143 | :steps:
144 | 1. Ensure the logrotate configuration file exists
145 | 2. Register insights-client
146 | 3. Run the logrotate command
147 | 4. Verify that 2 new log files were created
148 | 5. Verify the size of insights-client.log
149 | 6. Verify the size of insights-client-payload.log
150 | :expectedresults:
151 | 1. The logrotate config file exists
152 | 2. The insights-client is registered
153 | 3. The logrotate command is executed successfully
154 | 4. Two new log files were created
155 | 5. The size of insights-client.log is 0B
156 | 6. The size of insights-client-payload.log is 0B
157 | """
158 |
159 | logrotate_conf_file_path = "/etc/logrotate.d/insights-client"
160 | logdir = "/var/log/insights-client/"
161 | logfile_insights = f"{logdir}/insights-client.log"
162 | logfile_payload = f"{logdir}/insights-client-payload.log"
163 |
164 | assert os.path.exists(logrotate_conf_file_path), "logrotate is not configured"
165 | """
166 | It is necessary to perform some command using insights-client
167 | to populate logs.
168 | Save the archive, to be used while register operation using --keep-archive.
169 | for example-
170 | [root@test ~]# insights-client --register --keep-archive
171 | Automatic scheduling for Insights has been enabled.
172 | Starting to collect Insights data for test
173 | Writing RHSM facts to /etc/rhsm/facts/insights-client.facts ...
174 | Uploading Insights data.
175 | Successfully uploaded report for test.
176 | View the Red Hat Insights console at https://console.redhat.com/insights/
177 | Copying archive from /var/tmp/insights-client-qxl3vdqy/insights-test-date.tar.gz
178 | to /var/cache/insights-client/insights-test-date.tar.gz
179 | Insights archive retained in /var/cache/insights-client/insights-test-date.tar.gz
180 | """
181 | reg_result = insights_client.run("--register", "--keep-archive")
182 | assert conftest.loop_until(lambda: insights_client.is_registered)
183 |
184 | archive_name = reg_result.stdout.split()[-1]
185 | insights_client.run(
186 | f"--payload={archive_name}",
187 | "--content-type=gz",
188 | )
189 | number_of_log_files = len(os.listdir(logdir)) # count of files before rotation
190 |
191 | subprocess.check_call(["logrotate", "-vf", logrotate_conf_file_path])
192 | assert os.path.getsize(logfile_insights) == 0
193 | assert os.path.getsize(logfile_payload) == 0
194 | number_of_files_after_logrotate = len(os.listdir(logdir))
195 | assert number_of_files_after_logrotate == (number_of_log_files + 2)
196 |
197 |
198 | @pytest.mark.usefixtures("register_subman")
199 | @pytest.mark.tier1
200 | def test_insights_details_file_exists(insights_client):
201 | """
202 | :id: 2ccc8e00-0e76-47fd-bdb2-27998c0094ab
203 | :title: Verify insights-client details file exists
204 | :description: Verify that the file /var/lib/insights/insights-client.json exists
205 | :tags: Tier 1
206 | :steps:
207 | 1. Register insights-client
208 | 2. Delete /var/lib/insights/insights-client.json if it exists
209 | 3. Run the --check-results command
210 | 4. Verify the existence of /var/lib/insights/insights-client.json
211 | :expectedresults:
212 | 1. Insights-client is registered
213 | 2. The file /var/lib/insights/insights-client.json does not exist
214 | 3. The --check-results command is executed successfully
215 | 4. The file /var/lib/insights/insights-client.json exists
216 | """
217 | output_file = "/var/lib/insights/insights-details.json"
218 | insights_client.register()
219 | assert conftest.loop_until(lambda: insights_client.is_registered)
220 |
221 | # Deleting file manually
222 | with contextlib.suppress(FileNotFoundError):
223 | os.remove(output_file)
224 | insights_client.run("--check-results")
225 | # Verify that insights-details.json gets re generated
226 | assert os.path.isfile(output_file)
227 |
228 |
229 | @pytest.mark.usefixtures("register_subman")
230 | @pytest.mark.tier1
231 | def test_insights_directory_files(insights_client):
232 | """
233 | :id: 02072b65-9905-4426-96dc-76af6a73e14f
234 | :title: Verify insights directory files
235 | :description: Verify that the /var/lib/insights directory has the expected content
236 | :tags: Tier 1
237 | :steps:
238 | 1. Register insights-client
239 | 2. Check the content of /var/lib/insights directory
240 | 3. Verify specific files exists
241 | :expectedresults:
242 | 1. Insights-client is registered
243 | 2. The list of contents of /var/lib/insights directory is created
244 | 3. All specified files are present
245 | """
246 | directory = "/var/lib/insights"
247 | registered_contents = [
248 | "last_stable.egg",
249 | "last_stable.egg.asc",
250 | ]
251 |
252 | insights_client.register()
253 | assert conftest.loop_until(lambda: insights_client.is_registered)
254 |
255 | dir_content_registered = [
256 | entry.name for entry in os.scandir(directory) if entry.is_file()
257 | ]
258 |
259 | for item in registered_contents:
260 | assert item in dir_content_registered, f"File '{item}' not found in directory."
261 |
--------------------------------------------------------------------------------
/integration-tests/test_client_systemd.py:
--------------------------------------------------------------------------------
1 | """
2 | :casecomponent: insights-client
3 | :requirement: RHSS-291297
4 | :polarion-project-id: RHELSS
5 | :polarion-include-skipped: false
6 | :polarion-lookup-method: id
7 | :subsystemteam: rhel-sst-csi-client-tools
8 | :caseautomation: Automated
9 | :upstream: Yes
10 | """
11 |
12 | import conftest
13 | from time import sleep
14 | import pytest
15 | import subprocess
16 | from pathlib import Path
17 |
18 | pytestmark = pytest.mark.usefixtures("register_subman")
19 |
20 |
21 | @pytest.mark.tier1
22 | def test_data_upload_systemd_timer(insights_client, external_inventory):
23 | """
24 | :id: 6bbac679-cb37-47b1-9163-497f1a1758dd
25 | :title: Verify insights-client upload via systemd timer
26 | :description:
27 | Ensure that the insights-client data upload is triggered by the
28 | systemd timer and the last check-in time is updated accordingly
29 | :tags: Tier 1
30 | :steps:
31 | 1. Register the system
32 | 2. Note the last_check_in in host details from inventory
33 | 3. Edit insights-client timer to run every 3 minutes (24 hours is
34 | too long to wait for a test, 3 min appears be a decent wait)
35 | 4. Wait for upload to finish
36 | 5. Again note the last_check_in in host details from inventory
37 | 6. Verify the updated last_check_in time
38 | :expectedresults:
39 | 1. System is registered
40 | 2. The last_check_in time is recorded from the inventory
41 | 3. The timer is adjusted to a 3-minute interval and upload proceeds
42 | as expected.
43 | 4. Upload is finished successfully
44 | 5. The last_check_in time is recorded from the inventory
45 | 6. The last_check_in time is updated, reflecting a successful upload
46 | """
47 | insights_client.register()
48 | assert conftest.loop_until(lambda: insights_client.is_registered)
49 |
50 | machine_id = insights_client.uuid
51 | # fetching host details to note last_check_in time
52 | response = external_inventory.get(path=f"hosts?insights_id={machine_id}")
53 | host_staleness = response.json()["results"][0]["per_reporter_staleness"]
54 | last_checkin_time = host_staleness["puptoo"]["last_check_in"]
55 |
56 | # override insights-client.timer to run every 3 min
57 | override_path = Path("/etc/systemd/system/insights-client.timer.d/override.conf")
58 | override_content = """
59 | [Timer]
60 | OnCalendar=*:0/3
61 | Persistent=true
62 | RandomizedDelaySec=5
63 | """
64 | try:
65 | override_path.parent.mkdir()
66 | override_path.write_text(override_content)
67 |
68 | subprocess.run(["systemctl", "daemon-reload"])
69 |
70 | sleep(60 * 5) # sleep for the period when timer is triggered and upload happens
71 |
72 | # remove the override.conf for insights-client.timer to avoid multiple uploads
73 | subprocess.run(["systemctl", "revert", "insights-client.timer"])
74 |
75 | # fetch the last_check_in time
76 | response = external_inventory.this_system()
77 | latest_checkin_time = response["per_reporter_staleness"]["puptoo"][
78 | "last_check_in"
79 | ]
80 | assert last_checkin_time < latest_checkin_time
81 |
82 | finally:
83 | subprocess.run(["systemctl", "revert", "insights-client.timer"])
84 |
--------------------------------------------------------------------------------
/integration-tests/test_common_specs.py:
--------------------------------------------------------------------------------
1 | """
2 | :casecomponent: insights-client
3 | :requirement: RHSS-291297
4 | :polarion-project-id: RHELSS
5 | :polarion-include-skipped: false
6 | :polarion-lookup-method: id
7 | :subsystemteam: rhel-sst-csi-client-tools
8 | :caseautomation: Automated
9 | :upstream: Yes
10 | """
11 |
12 | import json
13 | import os
14 | import pytest
15 | import subprocess
16 | import logging
17 |
18 | pytestmark = pytest.mark.usefixtures("register_subman")
19 |
20 |
21 | @pytest.mark.tier1
22 | def test_common_specs(insights_client, tmp_path):
23 | """
24 | :id: 9010f731-ca05-4abb-b119-de9730b055c1
25 | :title: Test common specs
26 | :description:
27 | This test verifies that the specified specs can be collected,
28 | parsed and contain valid data without errors
29 | :tags: Tier 1
30 | :steps:
31 | 1. Define the list of common specs to be tested
32 | 2. Run the insights-client to collect data and save it in the
33 | specified temporary directory
34 | 3. For each spec in the list check that it exists in the
35 | correct location
36 | 4. Verify the spec file contains no errors
37 | 5. Verify the spec file has valid results
38 | :expectedresults:
39 | 1. The list of specs is correctly defined
40 | 2. The client runs and the data is saved in the tmp_path directory
41 | 3. Each spec file is found in the meta_data directory and none is missing
42 | 4. Data contains no errors (data["errors"] is empty or does not exist)
43 | 5. Each spec contains valid results (data["results"] is not None) confirming
44 | the data was successfully collected
45 | """
46 | common_specs = [
47 | "insights.specs.Specs.date.json",
48 | "insights.specs.Specs.hosts.json",
49 | "insights.specs.Specs.installed_rpms.json",
50 | "insights.specs.Specs.ls_dev.json",
51 | "insights.specs.Specs.lscpu.json",
52 | "insights.specs.Specs.lspci.json",
53 | "insights.specs.Specs.meminfo.json",
54 | "insights.specs.Specs.mount.json",
55 | "insights.specs.Specs.mountinfo.json",
56 | "insights.specs.Specs.ps_auxcww.json",
57 | "insights.specs.Specs.redhat_release.json",
58 | "insights.specs.Specs.uname.json",
59 | "insights.specs.Specs.yum_repos_d.json",
60 | ]
61 | # The following specs can't be collected in containers
62 | privileged_specs = [
63 | "insights.specs.Specs.dmidecode.json",
64 | "insights.specs.Specs.fstab.json",
65 | "insights.specs.Specs.hostname.json",
66 | "insights.specs.Specs.ip_addresses.json",
67 | ]
68 |
69 | # Running insights-client to collect data in tmp path
70 | insights_client.run(f"--output-dir={tmp_path}")
71 |
72 | in_container: bool = "container" in os.environ.keys()
73 | for spec in common_specs + privileged_specs:
74 | spec_filepath = tmp_path / "meta_data" / spec
75 |
76 | # assert that spec file exists
77 | assert os.path.exists(spec_filepath), f"spec file {spec} not found "
78 |
79 | with open(spec_filepath, "r") as specfile:
80 | data = json.load(specfile)
81 |
82 | # assert that a spec doesn't contain errors
83 | # (unless we are in container and the spec is known to not work in containers)
84 | if in_container and spec in privileged_specs:
85 | continue
86 |
87 | try:
88 | assert not data["errors"], f"'{spec}' contains errors: {data['errors']} "
89 | assert data["results"] is not None, f"'{spec}' does not contain results"
90 | except AssertionError as e:
91 | logging.error(f"Spec '{spec}' failed with an error '{str(e)}'")
92 |
93 | # Try to extract and re-run the command from the spec JSON
94 | cmd = data["results"]["object"]["cmd"]
95 | if cmd:
96 | logging.debug(f"Attempting to re-run the cmd from the spec: '{cmd}'")
97 | result = subprocess.run(
98 | cmd, shell=True, capture_output=True, text=True, timeout=10
99 | )
100 |
101 | logging.debug(f"Command return code: {result.returncode}")
102 | logging.debug(f"Command STDOUT code: {result.stdout.strip()}")
103 | logging.debug(f"Command STDERR code: {result.stderr.strip()}")
104 |
105 | if result.returncode != 0:
106 | raise AssertionError(
107 | f"Command '{cmd}' failed with a return code \
108 | of {result.returncode}"
109 | )
110 | else:
111 | logging.debug(f"No command found in spec JSON for {spec}")
112 | raise
113 |
--------------------------------------------------------------------------------
/integration-tests/test_compliance.py:
--------------------------------------------------------------------------------
1 | """
2 | :casecomponent: insights-client
3 | :requirement: RHSS-291297
4 | :polarion-project-id: RHELSS
5 | :polarion-include-skipped: false
6 | :polarion-lookup-method: id
7 | :subsystemteam: rhel-sst-csi-client-tools
8 | :caseautomation: Automated
9 | :upstream: Yes
10 | """
11 |
12 | import conftest
13 | import pytest
14 | import distro
15 |
16 | pytestmark = [
17 | pytest.mark.usefixtures("register_subman"),
18 | pytest.mark.skipif(
19 | distro.id() != "rhel",
20 | reason="Skipping tests because OS ID is not RHEL",
21 | allow_module_level=True,
22 | ),
23 | ]
24 |
25 |
26 | @pytest.mark.tier1
27 | def test_compliance_option(insights_client):
28 | """
29 | :id: caa8b3e1-9347-494c-a1f5-1fa670136834
30 | :title: Test compliance option
31 | :reference: https://issues.redhat.com/browse/CCT-1229
32 | :description:
33 | This test verifies that running the --compliance will not result in a failure
34 | :tags: Tier 1
35 | :steps:
36 | 1. Run insights-client with --compliance option
37 | 2. Register insights-client
38 | 3. Run insights-client with --compliance option
39 | :expectedresults:
40 | 1. Command will fail with instructions for user to register
41 | 2. System is successfully registered
42 | 3. The output of the command either informs user that system is not associated
43 | with any policies or the report will be successfully uploaded
44 | """
45 | compliance_before_registration = insights_client.run("--compliance", check=False)
46 | assert compliance_before_registration.returncode == 1
47 | assert (
48 | "This host is unregistered. Use --register to register this host"
49 | in compliance_before_registration.stdout
50 | or "This host has not been registered. Use --register to register this host"
51 | in compliance_before_registration.stdout
52 | )
53 |
54 | insights_client.register()
55 | assert conftest.loop_until(lambda: insights_client.is_registered)
56 |
57 | compliance_after_registration = insights_client.run("--compliance", check=False)
58 | if compliance_after_registration.returncode == 1:
59 | assert (
60 | "System is not associated with any policies."
61 | in compliance_after_registration.stdout
62 | )
63 | else:
64 | assert "Successfully uploaded report" in compliance_after_registration.stdout
65 |
66 |
67 | @pytest.mark.tier1
68 | def test_compliance_policies_option(insights_client):
69 | """
70 | :id: ad3a2073-3a2e-485e-bc7b-fede2111a06a
71 | :title: Test compliance-policies option
72 | :reference: https://issues.redhat.com/browse/CCT-1229
73 | :description:
74 | This test verifies that running the --compliance-policies
75 | will not result in a failure
76 | :tags: Tier 1
77 | :steps:
78 | 1. Register insights-client
79 | 2. Run insights-client with --compliance-policies option
80 | :expectedresults:
81 | 1. System is successfully registered
82 | 2. The output of the command either informs the user that system is not
83 | assignable to any policy or ID of available policy is found and
84 | displayed
85 | """
86 | insights_client.register()
87 | assert conftest.loop_until(lambda: insights_client.is_registered)
88 |
89 | compliance_policies = insights_client.run("--compliance-policies", check=False)
90 | if compliance_policies.returncode == 1:
91 | assert "System is not assignable to any policy." in compliance_policies.stdout
92 | assert (
93 | "Create supported policy using the Compliance web UI."
94 | in compliance_policies.stdout
95 | )
96 | else:
97 | assert "ID" in compliance_policies.stdout
98 |
--------------------------------------------------------------------------------
/integration-tests/test_connection.py:
--------------------------------------------------------------------------------
1 | """
2 | :casecomponent: insights-client
3 | :requirement: RHSS-291297
4 | :polarion-project-id: RHELSS
5 | :polarion-include-skipped: false
6 | :polarion-lookup-method: id
7 | :subsystemteam: rhel-sst-csi-client-tools
8 | :caseautomation: Automated
9 | :upstream: Yes
10 | """
11 |
12 | import configparser
13 | import contextlib
14 | import logging
15 | import os
16 | import typing
17 |
18 | import pytest
19 |
20 | if typing.TYPE_CHECKING:
21 | import pytest_client_tools.insights_client
22 |
23 | # the tests need a valid connection to insights so therefore the subman registration
24 | pytestmark = pytest.mark.usefixtures("register_subman")
25 |
26 |
27 | def _is_using_proxy(
28 | insights_config: "pytest_client_tools.insights_client.InsightsClientConfig",
29 | ) -> bool:
30 | for key, value in os.environ.items():
31 | if key.lower() == "https_proxy":
32 | logging.debug(f"Proxy is set via environment variable: '{value}'.")
33 | return True
34 |
35 | with contextlib.suppress(KeyError):
36 | insights_proxy: str = insights_config.proxy
37 | if insights_proxy != "":
38 | logging.debug(f"Proxy is set via insights-client: '{insights_proxy}'.")
39 | return True
40 |
41 | # sub-man fixture doesn't currently support reading the configuration file,
42 | # let's parse it ourselves.
43 | with contextlib.suppress(Exception):
44 | rhsm_config = configparser.ConfigParser()
45 | rhsm_config.read("/etc/rhsm/rhsm.conf")
46 | rhsm_proxy: str = rhsm_config.get("server", "proxy_hostname", fallback="")
47 | if rhsm_proxy != "":
48 | logging.debug(f"Proxy is set via subscription-manager: '{rhsm_proxy}'.")
49 | return True
50 |
51 | logging.debug("Proxy is not set.")
52 | return False
53 |
54 |
55 | @pytest.mark.tier1
56 | def test_connection_ok(insights_client):
57 | """
58 | :id: ff674d37-0ccc-481c-9f04-91237b8c50d0
59 | :title: Test connection
60 | :description:
61 | This test verifies that the --test-connection option works
62 | properly, confirming successful connection
63 | :tags: Tier 1
64 | :steps:
65 | 1. Run insights-client with --test-connection option
66 | 2. Verify that the connection to the upload URl is successful
67 | 3. Verify that the connection to the API URL is successful
68 | :expectedresults:
69 | 1. The command executes successfully
70 | 2. The output contains the expected output about upload connection
71 | 3. The output contains expected message about API URL connection
72 | """
73 | url_test = "End Upload URL Connection Test: SUCCESS"
74 | api_test = "End API URL Connection Test: SUCCESS"
75 |
76 | test_connection = insights_client.run("--test-connection")
77 | assert url_test in test_connection.stdout
78 | assert api_test in test_connection.stdout
79 |
80 |
81 | @pytest.mark.tier1
82 | def test_http_timeout(insights_client):
83 | """
84 | :id: 46c5fe2a-1553-4f2e-802d-fa10080c72df
85 | :title: Test HTTP timeout configuration
86 | :description:
87 | Verifies that setting a very low http_timeout value causes
88 | the connection to time out
89 | :tags: Tier 1
90 | :steps:
91 | 1. Set the http_timeout option to a very low value and save
92 | 2. Run insights-client with the --test-conection option
93 | 3. Verify that the command fails due to the low timeout setting
94 | 4. Check that the timeout value is in the output
95 | :expectedresults:
96 | 1. The http_timeout configuration is set and saved
97 | 2. The insights-client command is run
98 | 3. The command fails with a return code of 1
99 | 4. The output mentions timeout value
100 | """
101 | insights_client.config.http_timeout = 0.001
102 | insights_client.config.save()
103 |
104 | output = insights_client.run("--test-connection", check=False)
105 | assert output.returncode == 1
106 |
107 | if _is_using_proxy(insights_client.config):
108 | assert "timeout('timed out')" in output.stdout
109 | else:
110 | assert "Read timed out. (read timeout=0.001)"
111 | assert "Traceback" not in output.stdout
112 |
113 |
114 | @pytest.mark.tier1
115 | def test_noauth_proxy_connection(insights_client, test_config):
116 | """
117 | :id: a4bcb7e6-c04f-49d2-8362-525124dc61d9
118 | :title: Test no-auth proxy connection
119 | :description:
120 | Verifies that the insights-client can successfully connect
121 | through a no-auth proxy when using the --test-connection option
122 | :tags: Tier 1
123 | :steps:
124 | 1. Configure insights-client to use no-auth proxy and save
125 | 2. Run insights-client with the --test-connection option
126 | 3. Verify the connection to the upload URL is successful
127 | 4. Verify that the connection to the API URL is successful
128 | :expectedresults:
129 | 1. Insights-client is configured to use no-auth proxy
130 | 2. The command is executed successfully
131 | 3. The output mentions that the upload URL connection was suuccessful
132 | 4. The output mentions that the API URL connection test was successful
133 | """
134 | url_test = "End Upload URL Connection Test: SUCCESS"
135 | api_test = "End API URL Connection Test: SUCCESS"
136 |
137 | no_auth_proxy: str = (
138 | "http://"
139 | + test_config.get("noauth_proxy", "host")
140 | + ":"
141 | + str(test_config.get("noauth_proxy", "port"))
142 | )
143 | insights_client.config.proxy = no_auth_proxy
144 | insights_client.config.save()
145 |
146 | test_connection = insights_client.run("--test-connection")
147 | assert url_test in test_connection.stdout
148 | assert api_test in test_connection.stdout
149 |
150 |
151 | @pytest.mark.tier1
152 | def test_auth_proxy_connection(insights_client, test_config):
153 | """
154 | :id: 0b3e91d6-3b8b-42c7-8f3b-f7ee1728c311
155 | :title: Test auth-proxy connection
156 | :description:
157 | Verifies that the insights-client can successfully connect
158 | through an authenticated proxy
159 | :tags: Tier 1
160 | :steps:
161 | 1. Configure insights-client to use auth proxy and save
162 | 2. Run the insights-client with --test-connection option
163 | 3. Verify the connection to the upload URL is successful
164 | 4. Verify that the connection to the API URL is successful
165 | :expectedresults:
166 | 1. Insights-client is configured to use auth proxy
167 | 2. The command is executed successfully
168 | 3. The output mentions that the upload URL connection was suuccessful
169 | 4. The output mentions that the API URL connection test was successful
170 | """
171 | url_test = "End Upload URL Connection Test: SUCCESS"
172 | api_test = "End API URL Connection Test: SUCCESS"
173 |
174 | auth_proxy: str = (
175 | "http://"
176 | + test_config.get("auth_proxy", "username")
177 | + ":"
178 | + test_config.get("auth_proxy", "password")
179 | + "@"
180 | + test_config.get("auth_proxy", "host")
181 | + ":"
182 | + str(test_config.get("auth_proxy", "port"))
183 | )
184 | insights_client.config.proxy = auth_proxy
185 | insights_client.config.save()
186 | test_connection = insights_client.run("--test-connection")
187 | assert url_test in test_connection.stdout
188 | assert api_test in test_connection.stdout
189 |
190 |
191 | @pytest.mark.tier1
192 | def test_wrong_url_connection(insights_client):
193 | """
194 | :id: aa411b34-9af2-4759-ae05-756e9019c85e
195 | :title: Test wrong URL connection
196 | :description:
197 | Verifies that the insights-client fails to connect when an
198 | incorrect URL is configured
199 | :tags: Tier 1
200 | :steps:
201 | 1. Disable auto-configuration and auto-updates
202 | 2. Set an incorrect base URL in the configuration
203 | 3. Run insights-client with the --test-connection option
204 | 4. Verify the command fails due to the incorrect URL
205 | 5. Check that the output contains the appropriate failure message
206 | :expectedresults:
207 | 1. Auto-configuration and auto-updates are disabled
208 | 2. Incorrect base URL is set
209 | 3. Insights-client command is executed successfully
210 | 4. The command failed with a return code of 1
211 | 5. The message includes expected mentions of the failure
212 | """
213 | insights_client.config.auto_config = False
214 | insights_client.config.auto_update = False
215 | insights_client.config.base_url = "no-such-insights-url.example.com/something"
216 | insights_client.config.authmethod = "CERT"
217 | insights_client.config.save()
218 |
219 | test_connection = insights_client.run("--test-connection", check=False)
220 | assert test_connection.returncode == 1
221 |
222 | if _is_using_proxy(insights_client.config):
223 | assert "Cannot connect to proxy." in test_connection.stdout
224 | else:
225 | assert "Failed to establish a new connection" in test_connection.stdout
226 | assert "Connectivity test failed!" in test_connection.stdout
227 |
--------------------------------------------------------------------------------
/integration-tests/test_display_name_option.py:
--------------------------------------------------------------------------------
1 | """
2 | :casecomponent: insights-client
3 | :requirement: RHSS-291297
4 | :polarion-project-id: RHELSS
5 | :polarion-include-skipped: false
6 | :polarion-lookup-method: id
7 | :subsystemteam: rhel-sst-csi-client-tools
8 | :caseautomation: Automated
9 | :upstream: Yes
10 | """
11 |
12 | import string
13 | import pytest
14 | import uuid
15 | import logging
16 | import json
17 | import random
18 | import conftest
19 | import subprocess
20 |
21 | from constants import HOST_DETAILS
22 |
23 | logger = logging.getLogger(__name__)
24 |
25 | pytestmark = pytest.mark.usefixtures("register_subman")
26 |
27 |
28 | def read_host_details():
29 | with open(HOST_DETAILS, "r") as data_file:
30 | return json.load(data_file)
31 |
32 |
33 | def generate_unique_hostname():
34 | return f"test-qa.{uuid.uuid4()}.csi-client-tools.example.com"
35 |
36 |
37 | def create_random_string(n: int):
38 | return "".join(random.choices(string.ascii_letters, k=n))
39 |
40 |
41 | @pytest.mark.tier1
42 | def test_display_name(insights_client):
43 | """
44 | :id: 4758cb21-03b4-4334-852c-791b7c82b50a
45 | :title: Test updating display name via '--display-name'
46 | :description:
47 | This test verifies that a registered host's display name can be
48 | updated using the --display-name option.
49 | :tags: Tier 1
50 | :steps:
51 | 1. Generate a unique hostname and register the insights-client
52 | 2. Update the display name using --display-name
53 | 3. Verify the display name has been updated in the host details
54 | :expectedresults:
55 | 1. A unique hostname is generated and insights-client is registered
56 | 2. The command outputs 'Display name updated to '
57 | 3. The display_name in host detailes matches the new hostname
58 | """
59 | new_hostname = generate_unique_hostname()
60 | insights_client.run("--register")
61 | assert conftest.loop_until(lambda: insights_client.is_registered)
62 |
63 | response = insights_client.run("--display-name", new_hostname)
64 | logger.debug(f"response from console {response}")
65 |
66 | assert f"Display name updated to {new_hostname}" in response.stdout
67 |
68 | def display_name_changed():
69 | insights_client.run("--check-results")
70 | host_details = read_host_details()
71 | logger.debug(f"host details {host_details}")
72 | record = host_details["results"][0]
73 | return new_hostname == record["display_name"]
74 |
75 | assert conftest.loop_until(display_name_changed)
76 |
77 |
78 | @pytest.mark.tier1
79 | def test_register_with_display_name(insights_client):
80 | """
81 | :id: d127b2bf-2f6d-4b02-bb8e-99036bfc4291
82 | :title: Test registration with custom display name
83 | :description:
84 | This test ensures that registering the insights-client with a custom
85 | display name sets the display name correctly in host details
86 | :tags: Tier 1
87 | :steps:
88 | 1. Generate a unique hostname
89 | 2. Register the insights-client using '--register --display-name'
90 | 3. Verify the display_name in host details
91 | :expectedresults:
92 | 1. Unique hostname is generated
93 | 2. The client registers and successfully outputs the unique hostname
94 | 3. The display_name in host details matches the unique hostname
95 | """
96 | unique_hostname = generate_unique_hostname()
97 |
98 | status = insights_client.run("--register", "--display-name", unique_hostname)
99 | assert conftest.loop_until(lambda: insights_client.is_registered)
100 | assert unique_hostname in status.stdout
101 | insights_client.run("--check-results")
102 | host_details = read_host_details()
103 | logger.debug(f"content of host-details.json {host_details}")
104 |
105 | record = host_details["results"][0]
106 | assert "display_name" in record.keys()
107 | assert unique_hostname == record["display_name"]
108 |
109 |
110 | @pytest.mark.tier1
111 | def test_register_twice_with_different_display_name(
112 | insights_client, test_config, subtests
113 | ):
114 | """
115 | :id: 3d28562d-16c4-4fb1-b9b1-f39044e05ef5
116 | :title: Test re-registration with different display names
117 | :description:
118 | This test checks that registering the insights-client twice with different
119 | display names does not change the insights_id and display_name is updated
120 | :tags: Tier 1
121 | :steps:
122 | 1. Generate a unique hostname
123 | 2. Register the insights-client using '--register --display-name'
124 | 3. Record the machine ID and display_name
125 | 4. Generate another unique hostname
126 | 5. Register the insights-client using '--register --display_name'
127 | 6. Compare the old display_name and insights_id with those updated
128 | :expectedresults:
129 | 1. Unique hostname is generated
130 | 2. The client registers and successfully outputs the unique hostname
131 | 3. Information are successfully retrieved and stored
132 | 4. Unique hostname is generated
133 | 5. The output indicates that the host is already registered but updates the
134 | display_name to the new one
135 | 6. Insights_id stayed unchanged while display_name changed to the latest one
136 | """
137 | insights_id = None
138 | unique_hostname = generate_unique_hostname()
139 | unique_hostname_02 = generate_unique_hostname()
140 |
141 | with subtests.test(msg="the first registration"):
142 | status = insights_client.run("--register", "--display-name", unique_hostname)
143 | assert unique_hostname in status.stdout
144 |
145 | assert conftest.loop_until(lambda: insights_client.is_registered)
146 | insights_client.run("--check-results")
147 | host_details = read_host_details()
148 | record = host_details["results"][0]
149 | assert "display_name" in record.keys()
150 | assert unique_hostname == record["display_name"]
151 | insights_id = record["insights_id"]
152 |
153 | (status, host_details, record) = (None, None, None)
154 | with subtests.test(msg="The second registration"):
155 | status = insights_client.run("--register", "--display-name", unique_hostname_02)
156 | registration_message = "This host has already been registered"
157 | assert registration_message in status.stdout
158 |
159 | assert conftest.loop_until(lambda: insights_client.is_registered)
160 | insights_client.run("--check-results")
161 | host_details = read_host_details()
162 | logger.debug(f"content of host-details.json: {host_details}")
163 | record = host_details["results"][0]
164 | assert "display_name" in record.keys()
165 | assert unique_hostname_02 == record["display_name"]
166 | assert (
167 | insights_id == record["insights_id"]
168 | ), "machine-id should remain the same even display-name has been changed"
169 |
170 |
171 | @pytest.mark.parametrize("invalid_display_name", [create_random_string(201), ""])
172 | @pytest.mark.tier1
173 | def test_invalid_display_name(invalid_display_name, insights_client):
174 | """
175 | :id: 9cbdd1a6-9ee3-4799-baaf-15c3894ca55b
176 | :title: Test handling of invalid display names
177 | :parametrized: yes
178 | :description:
179 | This test verifies that attempting to set an invalid display_name is rejected
180 | and does not alter the current display_name value
181 | :tags: Tier 1
182 | :steps:
183 | 1. Register the insights-client
184 | 2. Record the original display_name value
185 | 3. Attempt to update the display_name using an invalid value
186 | 4. Verify that display_name stayed unchanged
187 | :expectedresults:
188 | 1. Insights-client is registered
189 | 2. Original display_name value is saved
190 | 3. The command fails with an error code 1 and a message
191 | 'Could not update display name'
192 | 4. The display_name in host details matches the saved original
193 | """
194 | insights_client.run("--register")
195 | assert conftest.loop_until(lambda: insights_client.is_registered)
196 |
197 | insights_client.run("--check-results")
198 | host_details = read_host_details()
199 | origin_display_name = host_details["results"][0]["display_name"]
200 |
201 | response = insights_client.run("--display-name", invalid_display_name, check=False)
202 | assert response.returncode == 1
203 | assert "Could not update display name" in response.stdout
204 |
205 | insights_client.run("--check-results")
206 | host_details = read_host_details()
207 | logger.debug(f"content of host-details.json {host_details}")
208 |
209 | record = host_details["results"][0]
210 | assert (
211 | origin_display_name == record["display_name"]
212 | ), "display-name should remain unchanged when new display-name is rejected"
213 |
214 |
215 | @pytest.mark.tier2
216 | def test_display_name_disable_autoconfig_and_autoupdate(insights_client, test_config):
217 | """
218 | :id: 8cdbc0ff-42ba-41e8-bd3f-31550ccac081
219 | :title: Test registration with display_name when auto-config and auto-update
220 | are disabled
221 | :description:
222 | This test verifies that the insights-client can be registered with a
223 | display_name name even when auto_config and auto_update are set to
224 | False and host appears on cloud with the correct display name
225 | :reference: https://issues.redhat.com/browse/RHEL-19435
226 | :tags: Tier 2
227 | :steps:
228 | 1. Configure insights-client.conf with auto_config and auto_update set to False
229 | and display_name set
230 | 2. Register the insights-client
231 | 3. Verify the host is visible in cloud.redhat.com with the correct display_name
232 | set in the configuration file
233 | :expectedresults:
234 | 1. Configuration is set and successfully saved
235 | 2. Insights-client is registered
236 | 3. Host appears in inventory with the display name matching the one that was set
237 | """
238 | # configuration on insights-client.conf
239 | insights_client.config.legacy_upload = False
240 | insights_client.config.cert_verify = True
241 | insights_client.config.auto_update = False
242 | insights_client.config.auto_config = False
243 | insights_client.config.authmethod = "CERT"
244 | unique_hostname = generate_unique_hostname()
245 | insights_client.config.display_name = unique_hostname
246 | if "satellite" in test_config.environment:
247 | satellite_hostname = test_config.get("candlepin", "host")
248 | satellite_port = test_config.get("candlepin", "port")
249 | insights_client.config.base_url = (
250 | satellite_hostname + ":" + str(satellite_port) + "/redhat_access/r/insights"
251 | )
252 | insights_client.config.cert_verify = "/etc/rhsm/ca/katello-server-ca.pem"
253 | elif "prod" in test_config.environment:
254 | insights_client.config.base_url = "cert.cloud.redhat.com/api"
255 | elif "stage" in test_config.environment:
256 | insights_client.config.base_url = "cert.cloud.stage.redhat.com/api"
257 | insights_client.config.save()
258 |
259 | # register insights
260 | try:
261 | status = insights_client.run("--register")
262 | except subprocess.CalledProcessError as e:
263 | if (
264 | "certificate verify failed" in e.stdout.lower()
265 | or "certificate verify failed" in str(e)
266 | ):
267 | pytest.skip("Skipping test due to SSL certificate verification failure")
268 | raise
269 | assert conftest.loop_until(lambda: insights_client.is_registered)
270 | assert unique_hostname in status.stdout
271 |
272 | # check the display name on CRC
273 | insights_client.run("--check-results")
274 | host_details = read_host_details()
275 | logger.debug(f"content of host-details.json {host_details}")
276 | record = host_details["results"][0]
277 | assert unique_hostname == record["display_name"]
278 |
--------------------------------------------------------------------------------
/integration-tests/test_e2e.py:
--------------------------------------------------------------------------------
1 | """
2 | :casecomponent: insights-client
3 | :requirement: RHSS-291297
4 | :polarion-project-id: RHELSS
5 | :polarion-include-skipped: false
6 | :polarion-lookup-method: id
7 | :subsystemteam: rhel-sst-csi-client-tools
8 | :caseautomation: Automated
9 | :upstream: Yes
10 | """
11 |
12 | import pytest
13 | import conftest
14 | from pytest_client_tools.util import Version
15 |
16 | pytestmark = pytest.mark.usefixtures("register_subman")
17 |
18 |
19 | @pytest.mark.tier1
20 | def test_insights_client_version_in_inventory(insights_client, external_inventory):
21 | """
22 | :id: 1d5d101e-94ad-4404-900f-f86a26450c3f
23 | :title: Verify insights-client version in Inventory
24 | :description:
25 | Ensure that running insights-client creates a new host entry in the
26 | Inventory and includes both the insights-client and egg version information
27 | :tags: Tier 1
28 | :steps:
29 | 1. Register the system with insights-client
30 | 2. Confirm registration status
31 | 3. Retrieve the system profile from the Inventory
32 | :expectedresults:
33 | 1. Insights-client is registered
34 | 2. The system profile is retrieved from the Inventory
35 | 3. The system profile includes insights-client and egg version information
36 | """
37 | insights_client.register()
38 | assert conftest.loop_until(lambda: insights_client.is_registered)
39 |
40 | system_profile = external_inventory.this_system_profile()
41 |
42 | assert insights_client.version == Version(system_profile["insights_client_version"])
43 | assert insights_client.core_version == Version(
44 | (system_profile["insights_egg_version"].split("-"))[0]
45 | )
46 |
--------------------------------------------------------------------------------
/integration-tests/test_file_workflow.py:
--------------------------------------------------------------------------------
1 | """
2 | :casecomponent: insights-client
3 | :requirement: RHSS-291297
4 | :polarion-project-id: RHELSS
5 | :polarion-include-skipped: false
6 | :polarion-lookup-method: id
7 | :subsystemteam: rhel-sst-csi-client-tools
8 | :caseautomation: Automated
9 | :upstream: Yes
10 | """
11 |
12 | import json
13 | import os
14 | import random
15 | import string
16 | import subprocess
17 | import tarfile
18 | from time import sleep
19 | import pytest
20 | from constants import HOST_DETAILS
21 | from constants import MACHINE_ID_FILE
22 | import conftest
23 | import logging
24 |
25 |
26 | pytestmark = pytest.mark.usefixtures("register_subman")
27 |
28 |
29 | @pytest.mark.tier1
30 | def test_file_workflow_with_an_archive_with_only_one_canonical_fact(
31 | insights_client, tmp_path
32 | ):
33 | """
34 | :id: 816e341e-2477-4f24-8e37-dacf308413f5
35 | :title: Test File Workflow with an Archive with only One Canonical Fact
36 | :description:
37 | Verify uploading an Insights Archive with just one
38 | canonical fact creates a new host on Inventory
39 | :tags: Tier 1
40 | :steps:
41 | 1. Remove canonical facts files from the pre-collected archive
42 | except the file that has the insights-id
43 | 2. Upload the pre-collected archive
44 | 3. Retrieve the system from Inventory
45 | :expectedresults:
46 | 1. The facts are removed
47 | 2. The pre-collected archive is successfully uploaded
48 | 3. The host FQDN returned in host data retrieved from Inventory on step 3
49 | matches the hostname set in the archive
50 | """
51 | archive_name = tmp_path / "archive.tar.gz"
52 | modified_archive = tmp_path / "archive_modified.tar.gz"
53 |
54 | insights_client.run(f"--output-file={archive_name}")
55 | # Sending archive only with Insights ID
56 | files_to_remove = [
57 | "/data/etc/machine-id",
58 | "/data/insights_commands/hostname",
59 | "/data/insights_commands/hostname_-f",
60 | "/data/insights_commands/subscription-manager_identity",
61 | ]
62 | machine_id = open(MACHINE_ID_FILE, "r").read()
63 | remove_files_from_archive(archive_name, files_to_remove, modified_archive)
64 | upload_result = insights_client.run(
65 | f"--payload={modified_archive}", "--content-type=gz", check=False
66 | )
67 | assert "Successfully uploaded report" in upload_result.stdout
68 |
69 | # once archive is uploaded system status changes to register
70 | assert conftest.loop_until(lambda: insights_client.is_registered)
71 |
72 | insights_client.run("--check-results") # to get host details from inventory
73 | with open(HOST_DETAILS, "r") as data_file:
74 | file_content = json.load(data_file)
75 |
76 | assert "count" in file_content.keys()
77 | assert file_content["count"] == 1
78 | assert "results" in file_content.keys()
79 | host_data = file_content["results"][0]
80 |
81 | assert host_data.get("insights_id") == machine_id
82 |
83 |
84 | @pytest.mark.tier1
85 | def test_file_workflow_with_an_archive_without_canonical_facts(
86 | insights_client, tmp_path
87 | ):
88 | """
89 | :id: 46428b70-7803-4fb6-b694-66c88a0236e3
90 | :title: Test File Workflow with an Archive without Canonical Facts
91 | :description:
92 | Verify uploading an Insights Archive without canonical facts
93 | does NOT create a new host on Inventory
94 | :tags: Tier 1
95 | :steps:
96 | 1. Remove all canonical facts files from the pre-collected archive
97 | 2. Upload the pre-collected archive
98 | :expectedresults:
99 | 1. The facts are removed
100 | 2. The pre-collected archive is successfully uploaded
101 | """
102 | archive_name = tmp_path / "archive.tar.gz"
103 | modified_archive = tmp_path / "archive_modified.tar.gz"
104 |
105 | insights_client.run(f"--output-file={archive_name}")
106 | files_to_remove = [
107 | "/data/etc/insights-client/machine-id",
108 | "/data/etc/machine-id",
109 | "/data/etc/redhat-release",
110 | "/data/insights_commands/hostname",
111 | "/data/insights_commands/hostname_-f",
112 | "/data/insights_commands/subscription-manager_identity",
113 | "/data/insights_commands/dmidecode_-s_system-uuid",
114 | "/data/insights_commands/ip_addr",
115 | "/data/insights_commands/hostname_-I",
116 | "/data/sys/class/net/eth0/address",
117 | "/data/sys/class/net/lo/address",
118 | ]
119 |
120 | remove_files_from_archive(archive_name, files_to_remove, modified_archive)
121 | upload_result = insights_client.run(
122 | f"--payload={modified_archive}", "--content-type=gz", check=False
123 | )
124 | assert "Successfully uploaded report" in upload_result.stdout
125 |
126 |
127 | @pytest.mark.skipif(
128 | "container" in os.environ.keys(),
129 | reason="Containers cannot change hostnames",
130 | )
131 | @pytest.mark.tier1
132 | def test_file_workflow_archive_update_host_info(insights_client, external_inventory):
133 | """
134 | :id: 336abff9-4263-4f1d-9448-2cd05d40a371
135 | :title: Verify Insights Archive Updates Host Information
136 | :description:
137 | Ensure that updating files within an Insights Archive reflects
138 | the correct host information, such as hostname, in the Inventory
139 | :tags: Tier 1
140 | :steps:
141 | 1. Register the system with insights-client and confirm data upload
142 | 2. Change the system hostname
143 | 3. Collect and upload the new archive
144 | 4. Retrieve host data from Inventory and verify fqdn
145 | :expectedresults:
146 | 1. The system is registered and the archive is uploaded successfully
147 | 2. The system hostname is updated successfully
148 | 3. A new archive is collected and uploaded successfully
149 | 4. The fqdn in the Inventory matches the updated hostname
150 | """
151 | insights_client.register()
152 | assert conftest.loop_until(lambda: insights_client.is_registered)
153 | current_hostname = subprocess.check_output("hostname", shell=True).decode().strip()
154 |
155 | # Set a new hostname
156 | new_hostname = set_hostname()
157 | fqdn = subprocess.check_output("hostname -f", shell=True).decode().strip()
158 | logging.debug(f"Assigned hostname: {new_hostname}, FQDN: {fqdn}")
159 |
160 | insights_client.run()
161 | sleep(30) # Wait for data to get reflected in inventory
162 | host_data = external_inventory.this_system()
163 | logging.debug(f"Host data from inventory: {host_data}")
164 |
165 | # New hostname matches the one in Inventory
166 | assert host_data.get("fqdn") == fqdn
167 |
168 | # Reset to the original hostname
169 | set_hostname(current_hostname)
170 |
171 |
172 | def remove_files_from_archive(original_archive, files_to_remove, modified_archive):
173 | with tarfile.open(original_archive, "r:gz") as tar:
174 | file_list = tar.getnames()
175 | dir_name = tar.getnames()[0]
176 | # append dirname to create absolute path names
177 | files_to_remove = [dir_name + item for item in files_to_remove]
178 | # Remove the specified files from the list
179 | files_to_keep = [f for f in file_list if f not in files_to_remove]
180 | # Create a new tar archive
181 | with tarfile.open(modified_archive, "w:gz") as new_tar:
182 | for member in tar.getmembers():
183 | if member.name in files_to_keep:
184 | new_tar.addfile(member, tar.extractfile(member))
185 |
186 |
187 | def set_hostname(hostname=None):
188 | if hostname is None:
189 | hostname = (
190 | "".join(random.choices(string.ascii_lowercase + string.digits, k=10))
191 | + "-new-hostname.example.com"
192 | )
193 |
194 | subprocess.run(["hostnamectl", "set-hostname", hostname], check=True)
195 | return hostname
196 |
--------------------------------------------------------------------------------
/integration-tests/test_manpage.py:
--------------------------------------------------------------------------------
1 | """
2 | :casecomponent: insights-client
3 | :requirement: RHSS-291297
4 | :polarion-project-id: RHELSS
5 | :polarion-include-skipped: false
6 | :polarion-lookup-method: id
7 | :subsystemteam: rhel-sst-csi-client-tools
8 | :caseautomation: Automated
9 | :upstream: Yes
10 | """
11 |
12 | import gzip
13 | import pytest
14 |
15 |
16 | @pytest.mark.parametrize(
17 | "option",
18 | [
19 | "--checkin",
20 | "--compliance",
21 | "--content-type",
22 | "--diagnosis",
23 | "--disable-schedule",
24 | "--display-name",
25 | "--enable-schedule",
26 | "--group",
27 | "--keep-archive",
28 | "--list-specs",
29 | "--net-debug",
30 | "--no-upload",
31 | "--offline",
32 | "--output-dir",
33 | "--output-file",
34 | "--payload",
35 | "--quiet",
36 | "--register",
37 | "--retry",
38 | "--show-results",
39 | "--silent",
40 | "--status",
41 | "--test-connection",
42 | "--unregister",
43 | "--validate",
44 | "--verbose",
45 | "--version",
46 | ],
47 | )
48 | @pytest.mark.tier1
49 | def test_manpage(option):
50 | """
51 | :id: bd8dbda3-930e-4081-b318-1e88b25e26ef
52 | :title: Test manual page entries for insights-client
53 | :parametrized: yes
54 | :description:
55 | This test verifies that the insights-client manual page includes
56 | all the specified options.
57 | :tags: Tier 1
58 | :steps:
59 | 1. Open the manual page
60 | 2. Verify that the specified options are present
61 | :expectedresults:
62 | 1. Manual page is opened successfully
63 | 2. All od the options are found in the manual page
64 | """
65 | file = "/usr/share/man/man8/insights-client.8.gz"
66 | opened_file = gzip.open(file, "rt")
67 | content = opened_file.read()
68 | assert option in content, f"Option {option} is not present"
69 |
--------------------------------------------------------------------------------
/integration-tests/test_motd.py:
--------------------------------------------------------------------------------
1 | """
2 | :casecomponent: insights-client
3 | :requirement: RHSS-291297
4 | :polarion-project-id: RHELSS
5 | :polarion-include-skipped: false
6 | :polarion-lookup-method: id
7 | :subsystemteam: rhel-sst-csi-client-tools
8 | :caseautomation: Automated
9 | :upstream: Yes
10 | """
11 |
12 | import contextlib
13 | import conftest
14 | import os
15 | import subprocess
16 | import pytest
17 |
18 |
19 | DOT_REGISTERED_PATH = "/etc/insights-client/.registered"
20 | DOT_UNREGISTERED_PATH = "/etc/insights-client/.unregistered"
21 |
22 | MOTD_PATH = "/etc/motd.d/insights-client"
23 | MOTD_SRC = "/etc/insights-client/insights-client.motd"
24 |
25 |
26 | @pytest.fixture
27 | def delete_special_files():
28 | """Clean special files before and after test.
29 |
30 | Since .registered and .unregistered files are usually ignored and
31 | do not affect the behavior of insights-client, the MOTD case is
32 | special and depends on them.
33 |
34 | To ensure the tests here are not affected by them, we remove them
35 | """
36 |
37 | def delete_files():
38 | with contextlib.suppress(FileNotFoundError):
39 | os.remove(DOT_REGISTERED_PATH)
40 | with contextlib.suppress(FileNotFoundError):
41 | os.remove(DOT_UNREGISTERED_PATH)
42 | with contextlib.suppress(FileNotFoundError):
43 | os.remove(MOTD_PATH)
44 |
45 | delete_files()
46 | yield
47 | delete_files()
48 |
49 |
50 | @pytest.mark.usefixtures("register_subman")
51 | @pytest.mark.usefixtures("delete_special_files")
52 | @pytest.mark.tier1
53 | def test_motd(insights_client):
54 | """
55 | :id: a66a93bb-bbd2-4db0-a2aa-2bb184b11187
56 | :title: Test MOTD file presence based on registration status
57 | :description:
58 | This test verifies that the MOTD file exists on an unregistered
59 | system and that it is appropriately removed or not recreated upon
60 | registration and unregistration
61 | :tags: Tier 1
62 | :steps:
63 | 1. Verify that MOTD file is present on an unregistered system
64 | 2. Register the insights-client
65 | 3. Verify the MOTD file does not exists after registration
66 | 4. Unregister the insights-client
67 | 5. Verify the MOTD file still does not exist after unregistration
68 | :expectedresults:
69 | 1. The MOTD file is present
70 | 2. The client registers successfully
71 | 3. The MOTD file is removed
72 | 4. The client unregisters successfully
73 | 5. The MOTD file is still not present
74 | """
75 | # If the system is not registered, the file should be present.
76 | insights_client.run("--status", check=False)
77 | assert os.path.exists(MOTD_PATH)
78 |
79 | # After registration, the file should not exist.
80 | insights_client.register()
81 | assert conftest.loop_until(lambda: insights_client.is_registered)
82 | assert not os.path.exists(MOTD_PATH)
83 |
84 | # The system was unregistered. Because .unregistered file exists,
85 | # the file should not be present.
86 | insights_client.unregister()
87 | assert not os.path.exists(MOTD_PATH)
88 |
89 |
90 | @pytest.mark.usefixtures("register_subman")
91 | @pytest.mark.usefixtures("delete_special_files")
92 | @pytest.mark.tier1
93 | def test_motd_dev_null(insights_client):
94 | """
95 | :id: 7d48df16-e1af-4158-8a33-1d2cbb9ed22d
96 | :title: Test MOTD remains untouched when symlinked to /dev/null
97 | :description:
98 | This tst ensures that of the MOTD file is a symbolic link to
99 | /dev/null, it is not modified or removed during the client's registration
100 | and unregistration processes
101 | :tags: Tier 1
102 | :steps:
103 | 1. Create a symlink from MOTD_PATH to /dev/null
104 | 2. Run insights-client with --status option
105 | 3. Register the insights-client
106 | 4. Unregister the insights-client
107 | :expectedresults:
108 | 1. The symlink is created successfully
109 | 2. Command runs successfully and MOTD remains a symlink to /dev/null
110 | 3. The client is registered and MOTD stayed unchanged
111 | 4. the client is unregistered and MOTD stayed unchanged
112 | """
113 | with contextlib.ExitStack() as stack:
114 | os.symlink(os.devnull, MOTD_PATH)
115 | stack.callback(os.unlink, MOTD_PATH)
116 |
117 | insights_client.run("--status", check=False)
118 | assert os.path.samefile(os.devnull, MOTD_PATH)
119 |
120 | insights_client.register()
121 | assert conftest.loop_until(lambda: insights_client.is_registered)
122 | assert os.path.samefile(os.devnull, MOTD_PATH)
123 |
124 | insights_client.unregister()
125 | assert os.path.samefile(os.devnull, MOTD_PATH)
126 |
127 |
128 | @pytest.mark.usefixtures("delete_special_files")
129 | @pytest.mark.tier1
130 | def test_motd_message():
131 | """
132 | :id: 56d12383-f7bb-4dbe-899c-a1cbd2172a30
133 | :title: Test MOTD message content for unregistered systems
134 | :description:
135 | This test ensures that on unregistered system, the MOTD provides users
136 | with complete instructions on how to register
137 | :reference: https://issues.redhat.com/browse/CCT-264
138 | :tags: Tier 1
139 | :steps:
140 | 1. Ensure the host is unregistered
141 | 2. Read the content of the MOTD file and verify that content matches
142 | the expected message
143 | :expectedresults:
144 | 1. The system is unregistered
145 | 2. The MOTD provides correct registration instructions
146 | """
147 | cmd = ["cat", MOTD_SRC]
148 | output = subprocess.check_output(cmd, universal_newlines=True)
149 | motd_msg = "Register this system with Red Hat Insights: rhc connect\n\n\
150 | Example:\n\
151 | # rhc connect --activation-key --organization \n\n\
152 | The rhc client and Red Hat Insights will enable analytics and additional\n\
153 | management capabilities on your system.\n\
154 | View your connected systems at https://console.redhat.com/insights\n\n\
155 | You can learn more about how to register your system \n\
156 | using rhc at https://red.ht/registration\n"
157 | assert output == motd_msg
158 |
--------------------------------------------------------------------------------
/integration-tests/test_obfuscation.py:
--------------------------------------------------------------------------------
1 | """
2 | :casecomponent: insights-client
3 | :requirement: RHSS-291297
4 | :polarion-project-id: RHELSS
5 | :polarion-include-skipped: false
6 | :polarion-lookup-method: id
7 | :subsystemteam: rhel-sst-csi-client-tools
8 | :caseautomation: Automated
9 | :upstream: Yes
10 | """
11 |
12 | import pytest
13 | import tarfile
14 | import logging
15 | import uuid
16 | import socket
17 |
18 | pytestmark = pytest.mark.usefixtures("register_subman")
19 |
20 |
21 | @pytest.mark.tier1
22 | def test_ip_obfuscation(insights_client, tmp_path):
23 | """
24 | :id: 59c073f7-d207-42ae-85ee-a7a5d6fc6f8d
25 | :title: Test IP obfuscation functionality
26 | :description:
27 | This test verifies that when IP obfuscation is enabled in the
28 | insights-client configuration, the system's IP address is not
29 | present in the collected archive
30 | :tags: Tier 1
31 | :steps:
32 | 1. Record the system's IP address
33 | 2. Disable obfuscation in the configuration
34 | 3. Run the insights-client and check archive for an IP address
35 | 4. Enable obfuscation in the configuration
36 | 5. Run the insights-client and check archive for an IP address
37 | :expectedresults:
38 | 1. The system's IP address is recorded
39 | 2. Configuration is updated and saved
40 | 3. The IP address is found in the collected archive
41 | 4. Configuration is updated and saved
42 | 5. The IP address is not found in the collected archive
43 | """
44 | # Record the system ip
45 | hostname = socket.gethostname()
46 | system_ip = socket.gethostbyname(hostname)
47 |
48 | # Check the ip in archive before obfuscating ip
49 | insights_client.config.obfuscate = False
50 | insights_client.config.save()
51 | assert check_obfuscated_info(insights_client, tmp_path, system_ip)
52 |
53 | # Obfuscate hostname: obfuscate=True
54 | insights_client.config.obfuscate = True
55 | insights_client.config.save()
56 |
57 | # Check the ip in archive after obfuscating ip
58 | assert not check_obfuscated_info(insights_client, tmp_path, system_ip)
59 |
60 |
61 | @pytest.mark.tier1
62 | def test_hostname_obfuscation(insights_client, tmp_path):
63 | """
64 | :id: 68196220-f633-4a40-8040-6924d0e71b46
65 | :title: Test hostname obfuscation functionality
66 | :description:
67 | This test verifies that when hostname obfuscation is enabled in the
68 | insights-client configuration, the system's hostname is not present
69 | in the collected archive
70 | :tags: Tier 1
71 | :steps:
72 | 1. Record the system's hostname
73 | 2. Disable hostname obfuscation in the configuration
74 | 3. Run the insights-client and check archive for a hostname
75 | 4. Enable hostname obfuscation in the configuration
76 | 5. Run the insights-client and check archive for a hostname
77 | :expectedresults:
78 | 1. The system's hostname is recorded
79 | 2. Configuration is updated and saved
80 | 3. The hostname is found in the collected archive
81 | 4. Configuration is updated and saved
82 | 5. The hostname is not found in the collected archive
83 | """
84 | # Record the system hostname
85 | system_hostname = socket.gethostname()
86 |
87 | # Check the hostname in archive before obfuscating hostname
88 | insights_client.config.obfuscate = False
89 | insights_client.config.obfuscate_hostname = False
90 | insights_client.config.save()
91 | assert check_obfuscated_info(insights_client, tmp_path, system_hostname)
92 |
93 | # Check the hostname in archive after obfuscating hostname
94 | insights_client.config.obfuscate = True
95 | insights_client.config.obfuscate_hostname = True
96 | insights_client.config.save()
97 | assert not check_obfuscated_info(insights_client, tmp_path, system_hostname)
98 |
99 |
100 | @pytest.mark.parametrize("password_file", ["/etc/redhat-release", "/etc/hosts"])
101 | @pytest.mark.tier1
102 | def test_password_obfuscation(insights_client, tmp_path, password_file):
103 | """
104 | :id: ad3f22b2-8792-45fb-abdd-d29d58db5c41
105 | :title: Test password obfuscation in collected files
106 | :parametrized: yes
107 | :description:
108 | This test ensures that sensitive information such as passwords is obfuscated
109 | in collected files, regardless of the obfuscation setting in the configuration
110 | file
111 | :tags: Tier 1
112 | :steps:
113 | 1. Backup the original content of the test file
114 | 2. Append a password string to the test file
115 | 3. Make sure obfuscation is disabled in the configuration file
116 | 4. Run the insights-client and check for the password in the archive
117 | 5. Enable obfuscation
118 | 6. Run the insights-client and check for the password in the archive
119 | 7. Restore the original content of the test file
120 | :expectedresults:
121 | 1. Original content is backed up
122 | 2. Password string is added without errors
123 | 3. Configuration is updated and saved
124 | 4. Password is not found in the test file
125 | 5. Configuration is updated and saved
126 | 6. Password is still not present in the test file
127 | 7. Original content is restored
128 | """
129 | # backup the original content of tested files
130 | with open(password_file, "r+") as f:
131 | original_content = f.read()
132 | try:
133 | # Add a line about password in a tested file
134 | password_string = "my-super-secret-password"
135 | with open(password_file, "a") as file:
136 | file.write(f"\npassword: {password_string}")
137 |
138 | # Make sure obfuscate=False
139 | insights_client.config.obfuscate = False
140 | insights_client.config.save()
141 |
142 | # the password value is not visible although obfuscate=False
143 | assert not check_obfuscated_info(insights_client, tmp_path, password_string)
144 |
145 | # the password value is not visible after Obfuscating IP
146 | insights_client.config.obfuscate = True
147 | insights_client.config.save()
148 | assert not check_obfuscated_info(insights_client, tmp_path, password_string)
149 | finally:
150 | with open(password_file, "w+") as f:
151 | f.write(original_content)
152 |
153 |
154 | @pytest.mark.parametrize(
155 | "package_info_file",
156 | [
157 | "data/insights_commands/rpm_-qa_--qf",
158 | "data/insights_commands/yum_-C_--noplugins_list_available",
159 | "data/insights_commands/yum_updates_list",
160 | "data/etc/dnf/modules.d/",
161 | ],
162 | )
163 | @pytest.mark.tier1
164 | def test_no_obfuscation_on_package_version(
165 | insights_client, tmp_path, package_info_file
166 | ):
167 | """
168 | :id: aa2eb4cf-9fed-4fe9-8423-87bbf2f2dd95
169 | :title: Test package versions are not obfuscated when obfuscation is enabled
170 | :parametrized: yes
171 | :description:
172 | This test ensures that version strings in package information files
173 | are not incorrectly obfuscated as IP addresses when obfuscation is
174 | enabled
175 | :reference: https://issues.redhat.com/browse/ESSNTL-444
176 | :tags: Tier 1
177 | :steps:
178 | 1. Enable obfuscation in the configuration file
179 | 2. Run the insights-client and collect the archive
180 | 3. Check the specified package information files in the archive
181 | :expectedresults:
182 | 1. Configuration is updated and saved
183 | 2. Archive is collected
184 | 3. Version strings are not obfuscated and are present
185 | """
186 | # Obfuscate IP
187 | insights_client.config.obfuscate = True
188 | insights_client.config.save()
189 |
190 | # Check if the package version is obfuscated by IP obfuscation
191 | archive_name = "test_archive_" + str(uuid.uuid4()) + ".tar.gz"
192 | archive_location = tmp_path / archive_name
193 | insights_client.run("--register", "--output-file=%s" % archive_location)
194 | with tarfile.open(archive_location, "r") as tar:
195 | for w_file in tar.getmembers():
196 | if w_file.name.find(package_info_file) != -1:
197 | file_content = tar.extractfile(w_file).read()
198 | assert "10.230.230" not in file_content.decode()
199 |
200 |
201 | @pytest.mark.tier1
202 | def test_no_obfuscation_on_display_name(insights_client, tmp_path):
203 | """
204 | :id: a5b73cba-928d-4e78-9792-6a667e5c4c2b
205 | :title: Test display_name is not obfuscated when obfuscation is enabled
206 | :description:
207 | This test ensures that display_name in package information files
208 | are not incorrectly obfuscated as IP addresses when obfuscation is
209 | enabled
210 | :tags: Tier 1
211 | :steps:
212 | 1. Enable obfuscation in the configuration file
213 | 2. Run the insights-client and collect the archive
214 | 3. Check the display_name information in the archive
215 | :expectedresults:
216 | 1. Configuration is updated and saved
217 | 2. Archive is collected
218 | 3. Display_name is not obfuscated and is present
219 | """
220 | # Set IP obfuscation and set display_name in insights-client.conf
221 | display_name_setting = "test_display_name" + str(uuid.uuid4())
222 | insights_client.config.obfuscate = True
223 | insights_client.config.display_name = display_name_setting
224 | insights_client.config.save()
225 |
226 | # Check the display_name in the archive
227 | archive_name = "test_archive_" + str(uuid.uuid4()) + ".tar.gz"
228 | archive_location = tmp_path / archive_name
229 | insights_client.run("--register", "--output-file=%s" % archive_location)
230 | with tarfile.open(archive_location, "r") as tar:
231 | for w_file in tar.getmembers():
232 | if w_file.name.endswith("display_name"):
233 | file_content = tar.extractfile(w_file).read().decode()
234 | assert display_name_setting in file_content
235 |
236 |
237 | def check_obfuscated_info(insights_client, tmp_path, info_to_search):
238 | archive_name = "test_archive_" + str(uuid.uuid4()) + ".tar.gz"
239 | archive_location = tmp_path / archive_name
240 | logging.info(archive_location)
241 | insights_client.run("--output-file=%s" % archive_location)
242 | info_exist = []
243 | with tarfile.open(archive_location, "r") as tar:
244 | for w_file in tar.getmembers():
245 | extracted_file = tar.extractfile(w_file)
246 | if (
247 | extracted_file is not None
248 | and info_to_search in extracted_file.read().decode()
249 | ):
250 | info_exist += [w_file.name]
251 | logging.info(info_exist)
252 | return info_exist
253 |
--------------------------------------------------------------------------------
/integration-tests/test_redaction.py:
--------------------------------------------------------------------------------
1 | """
2 | :casecomponent: insights-client
3 | :requirement: RHSS-291297
4 | :polarion-project-id: RHELSS
5 | :polarion-include-skipped: false
6 | :polarion-lookup-method: id
7 | :subsystemteam: rhel-sst-csi-client-tools
8 | :caseautomation: Automated
9 | :upstream: Yes
10 | """
11 |
12 | import pytest
13 | import subprocess
14 | import tarfile
15 | import os
16 | import yaml
17 | import uuid
18 | from enum import Enum
19 |
20 | pytestmark = pytest.mark.usefixtures("register_subman")
21 | TEST_CMD = ["/usr/bin/uptime", "/sbin/lsmod", "/bin/ls", "/sbin/ethtool"]
22 | TEST_FILE = ["/proc/cpuinfo", "/proc/meminfo", "/etc/os-release"]
23 | FILE_REDACTION_FILE = "/etc/insights-client/file-redaction.yaml"
24 | CONTENT_REDACTION_FILE = "/etc/insights-client/file-content-redaction.yaml"
25 |
26 |
27 | @pytest.mark.parametrize("not_removed_command", TEST_CMD)
28 | def test_redaction_not_on_cmd(insights_client, tmp_path, not_removed_command):
29 | """
30 | :id: 264d1d8f-47a5-49ce-800c-d349aaacdb01
31 | :title: Test commands are collected when redaction not configured
32 | :parametrized: yes
33 | :description:
34 | This test verifies that when no commands are configured for redaction in
35 | `/etc/insights-client/file-redaction.yaml`, the outputs of the related
36 | commands are included in the collection archive
37 | :tags: Tier 1
38 | :steps:
39 | 1. Ensure no command redaction is configured
40 | 2. Run the insights client to collect data
41 | 3. Check the archive for the specified command output
42 | :expectedresults:
43 | 1. No commands are specified for redaction in the configuration file
44 | 2. Data collection completes successfully
45 | 3. The output of the command is present in the archive
46 | """
47 | assert check_archive(insights_client, tmp_path, not_removed_command)
48 |
49 |
50 | @pytest.mark.parametrize("removed_command", TEST_CMD)
51 | def test_redaction_on_cmd(insights_client, tmp_path, removed_command):
52 | """
53 | :id: a2d7b71c-205d-4545-8a6b-b0be9ff57611
54 | :title: Test commands are redacted when configured
55 | :parametrized: yes
56 | :description:
57 | This test verifies that when commands are configured for redaction in
58 | `/etc/insights-client/file-redaction.yaml`, the outputs of the related
59 | commands are excluded from the collection archive
60 | :tags: Tier 1
61 | :steps:
62 | 1. Configure command redaction for the specified command
63 | 2. Run the insights client to collect data
64 | 3. Check the archive for the specified command output
65 | 4. Clean up by removing the redaction configuration file
66 | :expectedresults:
67 | 1. The command is added to the redaction configuration successfully
68 | 2. Data collection completes successfully
69 | 3. The output of the command is not present in the archive
70 | 4. Configuration file is removed successfully
71 | """
72 | try:
73 | configure_file_redaction("Command", removed_command)
74 | assert not check_archive(insights_client, tmp_path, removed_command)
75 | finally:
76 | os.remove(FILE_REDACTION_FILE)
77 |
78 |
79 | @pytest.mark.parametrize("not_removed_file", TEST_FILE)
80 | def test_redaction_not_on_file(insights_client, tmp_path, not_removed_file):
81 | """
82 | :id: cb2ee8b8-fd82-48ad-bebc-3e044f277c55
83 | :title: Test files are collected when redaction not configured
84 | :parametrized: yes
85 | :description:
86 | This test verifies that when no files are configured for redaction in
87 | `/etc/insights-client/file-redaction.yaml`, the related files are
88 | included in the collection archive
89 | :tags: Tier 1
90 | :steps:
91 | 1. Ensure no file redaction is configured
92 | 2. Run the insights client to collect data
93 | 3. Check the archive for the specified file
94 | :expectedresults:
95 | 1. No files are specified for redaction in the configuration file
96 | 2. Data collection completes successfully
97 | 3. The file is present in the archive
98 | """
99 | assert check_archive(insights_client, tmp_path, not_removed_file)
100 |
101 |
102 | @pytest.mark.parametrize("removed_file", TEST_FILE)
103 | @pytest.mark.tier1
104 | def test_redaction_on_file(insights_client, tmp_path, removed_file):
105 | """
106 | :id: 849cc4ac-d45e-44b8-b307-797935085eda
107 | :title: Test files are redacted when configured
108 | :parametrized: yes
109 | :description:
110 | This test verifies that when files are configured for redaction in
111 | `/etc/insights-client/file-redaction.yaml`, the related files are
112 | excluded from the collection archive
113 | :tags: Tier 1
114 | :steps:
115 | 1. Configure file redaction for the specified file
116 | 2. Run the insights client to collect data
117 | 3. Check the archive for the specified file
118 | 4. Clean up by removing the redaction configuration file
119 | :expectedresults:
120 | 1. The file is added to the redaction configuration successfully
121 | 2. Data collection completes successfully
122 | 3. The file is not present in the archive
123 | 4. Configuration file is removed successfully
124 | """
125 | try:
126 | configure_file_redaction("File", removed_file)
127 | assert not check_archive(insights_client, tmp_path, removed_file)
128 | finally:
129 | os.remove(FILE_REDACTION_FILE)
130 |
131 |
132 | @pytest.mark.skipif(
133 | "container" in os.environ.keys(),
134 | reason="Containers cannot change hostnames",
135 | )
136 | @pytest.mark.tier1
137 | def test_redaction_on_pattern_hostname(insights_client, tmp_path):
138 | """
139 | :id: 641edf11-ace1-4a98-9fb4-198cf9e5e4d0
140 | :title: Test hostname is redacted when pattern is configured
141 | :description:
142 | This test verifies that when a pattern matching the system's
143 | hostname is configured for content redaction in
144 | `/etc/insights-client/content-redaction.yaml`, the hostname is
145 | obfuscated in the collected data
146 | :reference: https://issues.redhat.com/browse/RHEL-2471
147 | :tags: Tier 1
148 | :steps:
149 | 1. Record the current system hostname
150 | 2. Set a new hostname for testing
151 | 3. Configure content redaction for the test hostname
152 | 4. Run the insights client and collect data
153 | 5. Check the archive to verify the hostname is redacted
154 | 6. Restore the original hostname and clean up
155 | :expectedresults:
156 | 1. The current hostname is recorded successfully
157 | 2. The system hostname is updated to the test hostname
158 | 3. The test hostname is added to the content redaction configuration
159 | 4. Data collection completes successfully
160 | 5. The test hostname is not present in the collected data
161 | 6. Original hostname is restored, and configuration files are removed
162 | """
163 | # Record the current hostname
164 | with open("/etc/hostname", "r") as f:
165 | previous_hostname = f.read().strip()
166 |
167 | try:
168 | # Set a new hostname
169 | hostname_to_test = "insights-client-host"
170 | set_hostname(hostname_to_test)
171 | cmd = ["hostnamectl", "status"]
172 | output = subprocess.check_output(cmd, universal_newlines=True)
173 | assert hostname_to_test in output
174 |
175 | # redaction on hostname:
176 | configure_content_redaction(hostname_to_test)
177 |
178 | # check the collection, if redaction pattern is filtered out
179 | archive_name = "test_archive_" + str(uuid.uuid4()) + ".tar.gz"
180 | archive_location = tmp_path / archive_name
181 | insights_client.run("--register", "--output-file=%s" % archive_location)
182 | with tarfile.open(archive_location, "r") as tar:
183 | for w_file in tar.getmembers():
184 | extracted_file = tar.extractfile(w_file)
185 | if extracted_file is not None:
186 | file_content = extracted_file.read().decode()
187 | assert hostname_to_test not in file_content
188 |
189 | finally:
190 | set_hostname(previous_hostname)
191 | os.remove(CONTENT_REDACTION_FILE)
192 |
193 |
194 | def check_archive(insights_client, tmp_path, tested):
195 | archive_location = tmp_path / "test_archive.tar.gz"
196 | insights_client.run("--output-file=%s" % archive_location)
197 | check_file = "/" + tested.split("/")[-1]
198 | if check_file == "/ls":
199 | check_file = "/ls_"
200 | with tarfile.open(archive_location, "r") as tar:
201 | check_tested = [
202 | file_name for file_name in tar.getnames() if check_file in file_name
203 | ]
204 | return check_tested
205 |
206 |
207 | def configure_file_redaction(type, redaction_string):
208 | redaction_type = Enum("redaction_type", ["Command", "File"])
209 | if type == redaction_type.Command.name:
210 | file_content = {"commands": [redaction_string]}
211 | elif type == redaction_type.File.name:
212 | file_content = {"files": [redaction_string]}
213 | with open(FILE_REDACTION_FILE, "w") as f:
214 | yaml.dump(file_content, f, default_flow_style=False)
215 | os.chmod(FILE_REDACTION_FILE, 0o600)
216 |
217 |
218 | def configure_content_redaction(pattern_string):
219 | file_content = {"patterns": {"regex": [pattern_string]}}
220 | with open(CONTENT_REDACTION_FILE, "w") as f:
221 | yaml.dump(file_content, f, default_flow_style=False)
222 | os.chmod(CONTENT_REDACTION_FILE, 0o600)
223 |
224 |
225 | def set_hostname(hostname_to_set):
226 | cmd = ["hostnamectl", "set-hostname", hostname_to_set]
227 | subprocess.check_call(cmd)
228 |
--------------------------------------------------------------------------------
/integration-tests/test_status.py:
--------------------------------------------------------------------------------
1 | """
2 | :casecomponent: insights-client
3 | :requirement: RHSS-291297
4 | :polarion-project-id: RHELSS
5 | :polarion-include-skipped: false
6 | :polarion-lookup-method: id
7 | :subsystemteam: rhel-sst-csi-client-tools
8 | :caseautomation: Automated
9 | :upstream: Yes
10 | """
11 |
12 | import conftest
13 | from constants import REGISTERED_FILE, UNREGISTERED_FILE, MACHINE_ID_FILE
14 | import contextlib
15 | import os
16 | import pytest
17 | from pytest_client_tools.util import Version
18 | from time import sleep
19 |
20 | pytestmark = pytest.mark.usefixtures("register_subman")
21 |
22 |
23 | @pytest.mark.tier1
24 | def test_status_registered(external_candlepin, insights_client):
25 | """
26 | :id: 624b01fc-e841-4c26-afd8-bb28eaf7fe75
27 | :title: Test insights-client --status when registered
28 | :description:
29 | This test verifies that when the insights client is registered, the
30 | `insights-client --status` command outputs the correct registration status
31 | :tags: Tier 1
32 | :steps:
33 | 1. Register the insights-client
34 | 2. Wait briefly to ensure inventory is up-to-date
35 | 3. Run `insights-client --status` command
36 | :expectedresults:
37 | 1. The client registers successfully
38 | 2. Wait time completes without issues
39 | 3. If 'legacy_upload' is True, output contains "Insights API confirms
40 | registration." If 'legacy_upload' is False, output is "This host
41 | is registered."
42 | """
43 | insights_client.register()
44 | assert conftest.loop_until(lambda: insights_client.is_registered)
45 | # Adding a small wait to ensure inventory is up-to-date
46 | sleep(5)
47 | registration_status = insights_client.run("--status")
48 | if insights_client.config.legacy_upload:
49 | assert "Insights API confirms registration." in registration_status.stdout
50 | else:
51 | assert "This host is registered.\n" == registration_status.stdout
52 |
53 |
54 | @pytest.mark.tier1
55 | def test_status_registered_only_locally(
56 | external_candlepin, insights_client, external_inventory
57 | ):
58 | """
59 | :id: 2ca3be87-8322-47b8-b451-9ea7fa3dbeef
60 | :title: Test insights-client --status when registered only locally
61 | :description:
62 | This test verifies that when the insights client is registered only
63 | locally, the `insights-client --status` command outputs the correct
64 | registration status
65 | :tags: Tier 1
66 | :steps:
67 | 1. Set the legacy_upload to False
68 | 2. Register the insights-client
69 | 3. Delete the host from the Inventory
70 | 4. Run `insights-client --status` command
71 | :expectedresults:
72 | 1. The client registers successfully
73 | 2. Wait time completes without issues
74 | 3. The host is deleted from the Inventory
75 | 4. On systems with version 3.5.7 and higher, output is "This host is
76 | registered.", the registered file exists, the unregistered file
77 | does not exist, and the machine ID file exists. Otherwise, output
78 | is "This host is unregistered."
79 | """
80 | insights_client.config.legacy_upload = False
81 | insights_client.register()
82 | assert conftest.loop_until(lambda: insights_client.is_registered)
83 | machine_id = insights_client.uuid
84 | external_inventory.delete(path=f"hosts/{external_inventory.this_system()['id']}")
85 | response = external_inventory.get(path=f"hosts?insights_id={machine_id}")
86 | assert response.json()["total"] == 0
87 |
88 | registration_status = insights_client.run("--status", check=False)
89 | if insights_client.core_version >= Version(3, 5, 7):
90 | assert "This host is registered.\n" == registration_status.stdout
91 | assert os.path.exists(REGISTERED_FILE)
92 | assert not os.path.exists(UNREGISTERED_FILE)
93 | assert os.path.exists(MACHINE_ID_FILE)
94 | else:
95 | assert "This host is unregistered.\n" == registration_status.stdout
96 |
97 |
98 | @pytest.mark.tier1
99 | def test_status_unregistered(external_candlepin, insights_client):
100 | """
101 | :id: aa37831a-a581-44db-a7c9-de8161767c7e
102 | :title: Test insights-client --status when unregistered
103 | :description:
104 | This test verifies that when the insights client is unregistered, the
105 | `insights-client --status` command outputs the correct unregistration
106 | status
107 | :tags: Tier 1
108 | :steps:
109 | 1. Unregister the insights client to ensure it's unregistered
110 | 2. Run `insights-client --status` command
111 | :expectedresults:
112 | 1. The client unregisters successfully
113 | 2. If 'legacy_upload' is True, return code is 1 and output contains
114 | "Insights API says this machine is NOT registered."
115 | If 'legacy_upload' is False, on systems with version 3.5.3 and
116 | higher, return code is 1 and output contains "This host is
117 | unregistered.". Otherwise return code is 0 and output contains
118 | "This host is unregistered."
119 | """
120 | # running unregistration to ensure system is unregistered
121 | with contextlib.suppress(Exception):
122 | insights_client.unregister()
123 | assert conftest.loop_until(lambda: not insights_client.is_registered)
124 |
125 | registration_status = insights_client.run("--status", check=False)
126 | if insights_client.config.legacy_upload:
127 | assert registration_status.returncode == 1
128 | assert (
129 | "Insights API says this machine is NOT registered."
130 | in registration_status.stdout
131 | )
132 | else:
133 | if insights_client.core_version >= Version(3, 5, 3):
134 | assert registration_status.returncode == 1
135 | else:
136 | assert registration_status.returncode == 0
137 | assert "This host is unregistered.\n" == registration_status.stdout
138 |
--------------------------------------------------------------------------------
/integration-tests/test_tags.py:
--------------------------------------------------------------------------------
1 | """
2 | :casecomponent: insights-client
3 | :requirement: RHSS-291297
4 | :polarion-project-id: RHELSS
5 | :polarion-include-skipped: false
6 | :polarion-lookup-method: id
7 | :subsystemteam: rhel-sst-csi-client-tools
8 | :caseautomation: Automated
9 | :upstream: Yes
10 | """
11 |
12 | import pytest
13 | import conftest
14 | import contextlib
15 | import os
16 | import yaml
17 | from constants import TAGS_FILE
18 | from time import sleep
19 |
20 | pytestmark = pytest.mark.usefixtures("register_subman")
21 |
22 |
23 | @pytest.mark.tier1
24 | def test_tags(insights_client, external_inventory, test_config):
25 | """
26 | :id: 3e9d5b76-7065-4ade-8397-5854a8fef83b
27 | :title: Test tags
28 | :description:
29 | Test how the tags generated, and check the tags on inventory
30 | :tags: Tier 1
31 | :steps:
32 | 1. Register insights-client, and check satellite related tags
33 | on the inventory if the test env is satellte.
34 | 2. Run insights-client with the --group
35 | 3. Add a new tag in tags.yaml, and run insights-client,
36 | then check the inventory
37 | :expectedresults:
38 | 1. System is registered to insights, and there will be
39 | satellite related tags supported by branch_info with
40 | satellite env.
41 | 2. tags.yaml will be created with group option, and new tag
42 | generated by tags.yaml
43 | 3. The new tag shows on inventory by modifying tags.yaml
44 | """
45 | # Remove the tags.yaml if it exists
46 | with contextlib.suppress(FileNotFoundError):
47 | TAGS_FILE.unlink()
48 |
49 | # Register insights
50 | insights_client.register()
51 | assert conftest.loop_until(lambda: insights_client.is_registered)
52 |
53 | # When test env is satellite, check the tags from branch_info
54 | # the tags from satellite are not generated by tags.yaml
55 | if "satellite" in test_config.environment:
56 | insights_client.run()
57 | system_tags = external_inventory.this_system_tags()
58 | for tag in system_tags:
59 | assert tag["namespace"] == "satellite"
60 | assert not TAGS_FILE.exists()
61 |
62 | with contextlib.ExitStack() as stack:
63 | # Run insights-client --group
64 | insights_client.run("--group=first_tag")
65 | stack.callback(os.remove, TAGS_FILE)
66 | assert TAGS_FILE.exists()
67 | with TAGS_FILE.open("r") as tags_yaml:
68 | data_loaded = yaml.safe_load(tags_yaml)
69 | assert data_loaded["group"] == "first_tag"
70 |
71 | # Check new tag from inventory
72 | sleep(30)
73 | system_tags = external_inventory.this_system_tags()
74 | assert {
75 | "namespace": "insights-client",
76 | "key": "group",
77 | "value": "first_tag",
78 | } in system_tags
79 |
80 | # Add new tag in tags.yaml file and check on inventory
81 | with TAGS_FILE.open("r") as tags_yaml:
82 | data_loaded = yaml.safe_load(tags_yaml)
83 | data_loaded["add_by_file"] = "second_tag"
84 | with TAGS_FILE.open("w") as tags_yaml:
85 | yaml.dump(data_loaded, tags_yaml, default_flow_style=False)
86 | insights_client.run()
87 | sleep(60)
88 | system_tags = external_inventory.this_system_tags()
89 | assert {
90 | "namespace": "insights-client",
91 | "key": "add_by_file",
92 | "value": "second_tag",
93 | } in system_tags
94 |
--------------------------------------------------------------------------------
/integration-tests/test_unregister.py:
--------------------------------------------------------------------------------
1 | """
2 | :casecomponent: insights-client
3 | :requirement: RHSS-291297
4 | :polarion-project-id: RHELSS
5 | :polarion-include-skipped: false
6 | :polarion-lookup-method: id
7 | :subsystemteam: rhel-sst-csi-client-tools
8 | :caseautomation: Automated
9 | :upstream: Yes
10 | """
11 |
12 | import pytest
13 | from pytest_client_tools.util import Version
14 | import conftest
15 |
16 | pytestmark = pytest.mark.usefixtures("register_subman")
17 |
18 |
19 | @pytest.mark.tier1
20 | def test_unregister(insights_client):
21 | """
22 | :id: ecaeeddc-4c8b-4f17-8d69-1c81d2c7c744
23 | :title: Test unregister
24 | :description:
25 | This test verifies that the insights-client can be unregistered
26 | successfully after being registered.
27 | :tags: Tier 1
28 | :steps:
29 | 1. Register the insights-client if not registered
30 | 2. Run `insights-client --unregister` command
31 | 3. Confirm the client is unregistered
32 | :expectedresults:
33 | 1. The client registers successfully
34 | 2. On systems with Insights Core version >= 3.5.11, the command outputs
35 | "Successfully unregistered this host." Otherwise, the command
36 | outputs "Successfully unregistered from the Red Hat Insights Service"
37 | 3. Client unregistration is confirmed
38 | """
39 | insights_client.register()
40 | assert conftest.loop_until(lambda: insights_client.is_registered)
41 |
42 | unregistration_status = insights_client.run("--unregister")
43 | if insights_client.core_version >= Version(3, 5, 11):
44 | assert "Successfully unregistered this host." in unregistration_status.stdout
45 | else:
46 | assert (
47 | "Successfully unregistered from the Red Hat Insights Service"
48 | in unregistration_status.stdout
49 | )
50 | assert conftest.loop_until(lambda: not insights_client.is_registered)
51 |
52 |
53 | @pytest.mark.tier1
54 | def test_unregister_twice(insights_client):
55 | """
56 | :id: bfff1b33-5f19-42d2-a6ff-4598975873e5
57 | :title: Test unregister already unregistered system
58 | :description:
59 | This test verifies that attempting to unregister the insights client
60 | when it is already unregistered behaves as expected. It checks that
61 | the first unregistration succeeds and that subsequent unregistration
62 | attempts produce the appropriate error message and return code
63 | :tags: Tier 1
64 | :steps:
65 | 1. Register the insights-client
66 | 2. Unregister the client for the first time
67 | 3. Attempt to unregister the client a second time
68 | :expectedresults:
69 | 1. The client registers successfully
70 | 2. On systems with Insights Core version >= 3.5.11, the command outputs
71 | "Successfully unregistered this host." Otherwise, the command
72 | outputs "Successfully unregistered from the Red Hat Insights Service"
73 | 3. Command returns exit code 1 and outputs "This host is not registered,
74 | unregistration is not applicable."
75 | """
76 | insights_client.register()
77 | assert conftest.loop_until(lambda: insights_client.is_registered)
78 |
79 | # unregister once
80 | unregistration_status = insights_client.run("--unregister")
81 | assert conftest.loop_until(lambda: not insights_client.is_registered)
82 | if insights_client.core_version >= Version(3, 5, 11):
83 | assert "Successfully unregistered this host." in unregistration_status.stdout
84 | else:
85 | assert (
86 | "Successfully unregistered from the Red Hat Insights Service"
87 | in unregistration_status.stdout
88 | )
89 |
90 | # unregister twice
91 | unregistration_status = insights_client.run("--unregister", check=False)
92 | assert conftest.loop_until(lambda: not insights_client.is_registered)
93 | assert unregistration_status.returncode == 1
94 | assert (
95 | "This host is not registered, unregistration is not applicable."
96 | in unregistration_status.stdout
97 | )
98 |
--------------------------------------------------------------------------------
/integration-tests/test_upload.py:
--------------------------------------------------------------------------------
1 | """
2 | :casecomponent: insights-client
3 | :requirement: RHSS-291297
4 | :polarion-project-id: RHELSS
5 | :polarion-include-skipped: false
6 | :polarion-lookup-method: id
7 | :subsystemteam: rhel-sst-csi-client-tools
8 | :caseautomation: Automated
9 | :upstream: Yes
10 | """
11 |
12 | import os
13 | import pytest
14 | import conftest
15 |
16 | pytestmark = pytest.mark.usefixtures("register_subman")
17 |
18 |
19 | @pytest.mark.tier1
20 | def test_upload_pre_collected_archive(insights_client, tmp_path):
21 | """
22 | :id: 9eba5a67-d013-4d43-98c7-c41ed38bcede
23 | :title: Test Upload of Pre-Collected Archive
24 | :description:
25 | This test verifies that a pre-collect insights-archive
26 | can be uploaded using --payload operation.
27 | :tags: Tier 1
28 | :steps:
29 | 1. Register insights-client
30 | 2. Run insights-client in an offline mode to generate an archive
31 | and save it
32 | 3. Run the insights-client with the --payload option and valid --content-type
33 | 4. Verify the successful upload of the archive
34 | :expectedresults:
35 | 1. Insights-client is registered
36 | 2. The archive is successfully generated and saved
37 | 3. The upload process starts and the output message is as expected
38 | 4. The upload completes successfully with the message as expected
39 | """
40 | archive_name = "archive.tar.gz"
41 | archive_location = tmp_path / archive_name
42 |
43 | # Registering the client because upload can happen on registered system
44 | insights_client.register()
45 | assert conftest.loop_until(lambda: insights_client.is_registered)
46 |
47 | # Running insights-client in offline mode to generate archive and save at tmp dir
48 | insights_client.run(f"--output-file={archive_location}")
49 |
50 | # Running insights-client --payload with --content-type to upload archive
51 | # collected in previous step
52 | upload_result = insights_client.run(
53 | f"--payload={archive_location}", "--content-type=gz"
54 | )
55 | assert "Uploading Insights data." in upload_result.stdout
56 | assert "Successfully uploaded report" in upload_result.stdout
57 |
58 |
59 | @pytest.mark.tier1
60 | def test_upload_wrong_content_type(insights_client, tmp_path):
61 | """
62 | :id: bb9ee84a-d262-4c42-ae16-9b45bf5a385c
63 | :title: Test Upload with Wrong Content Type
64 | :description:
65 | This test verifies that uploading an archive with wrong content
66 | type throws appropriate error message. Generate an archive and upload using
67 | --payload but wrong --content-type
68 | :tags: Tier 1
69 | :steps:
70 | 1. Register insights-client
71 | 2. Run the insights-client in offline mode to generate an archive and save it
72 | 3. Run the insights-client with --payload option and invalid --content-type
73 | 4. Run the insigts-client with a valid --content-type but different from
74 | compressor used
75 | :expectedresults:
76 | 1. Insights-client is registered
77 | 2. The archive is generated and saved
78 | 3. The upload process fails with the appropriate message
79 | 4. The upload process fails with the appropriate message
80 | """
81 | archive_name = "archive.tar.gz"
82 | archive_location = tmp_path / archive_name
83 |
84 | # Registering the client because upload can happen on registered system
85 | insights_client.register()
86 | assert conftest.loop_until(lambda: insights_client.is_registered)
87 |
88 | # Running insights-client in offline mode to generate archive and save at tmp dir
89 | insights_client.run(f"--output-file={archive_location}")
90 |
91 | # Running insights-client --payload with invalid --content-type to upload archive
92 | # collected in previous step
93 | upload_result = insights_client.run(
94 | f"--payload={archive_location}", "--content-type=bzip", check=False
95 | )
96 | assert "Invalid content-type." in upload_result.stdout
97 |
98 | # trying to upload with a valid content type but different from compressor
99 | upload_result = insights_client.run(
100 | f"--payload={archive_location}", "--content-type=xz", check=False
101 | )
102 | assert "Content type different from compression" in upload_result.stdout
103 |
104 |
105 | @pytest.mark.tier1
106 | def test_upload_too_large_archive(insights_client, tmp_path):
107 | """
108 | :id: bb9ee84a-d262-4c42-ae16-9b45bf5a385c
109 | :title: Test Upload of Too Large Archive
110 | :description:
111 | This test verifies that an attempt to upload too large archive
112 | results in failure
113 | :tags: Tier 1
114 | :steps:
115 | 1. Register insights-client
116 | 2. Create a large archive file in the temporary directory
117 | 3. Run insights-client with --payload option and --content-type
118 | pointing to the archive
119 | :expectedresults:
120 | 1. Insights-client is registered
121 | 2. A large archive is created in the temporary directory
122 | 3. The upload process fails with an appropriate message
123 | """
124 | insights_client.register()
125 | assert conftest.loop_until(lambda: insights_client.is_registered)
126 |
127 | file_path = tmp_path / "large_file.tar.gz"
128 | file_size = 100 * 1024 * 1024 # 100mb
129 | with open(file_path, "wb") as f:
130 | f.seek(int(file_size) + 1)
131 | f.write(b"\0")
132 |
133 | upload_result = insights_client.run(
134 | f"--payload={file_path}", "--content-type=gz", check=False
135 | )
136 |
137 | assert "Archive is too large to upload" in upload_result.stdout
138 | assert "Upload failed." in upload_result.stdout
139 |
140 |
141 | @pytest.mark.parametrize(
142 | "compressor,expected_extension",
143 | [
144 | ("gz", ".gz"),
145 | ("bz2", ".bz2"),
146 | ("xz", ".xz"),
147 | ],
148 | )
149 | @pytest.mark.tier1
150 | def test_upload_compressor_options(
151 | insights_client,
152 | compressor,
153 | expected_extension,
154 | ):
155 | """
156 | :id: 69a06826-6093-46de-a7a6-9726ae141820
157 | :title: Test upload with Different Compressor Options
158 | :parametrized: yes
159 | :description:
160 | This test verifies that valid compression types can be used
161 | with --compressor to create archives and upload data using --payload
162 | :tags: Tier 1
163 | :steps:
164 | 1. Register insights-client
165 | 2. Run insights-client with --compressor option to generate an archive
166 | with specified type
167 | 3. Verify the archive has the correct file extension based on the compression
168 | type
169 | :expectedresults:
170 | 1. Insights-client is registered
171 | 2. The archive is successfully generated
172 | 3. The file has expected file extension
173 | """
174 | insights_client.register()
175 | assert conftest.loop_until(lambda: insights_client.is_registered)
176 |
177 | # using --compressor option to generate and save archive
178 | command_result = insights_client.run(f"--compressor={compressor}", "--no-upload")
179 | archive_name = command_result.stdout.split()[-1]
180 |
181 | # Verifying that archive is created with expected extension
182 | assert os.path.splitext(archive_name)[1] == expected_extension
183 | assert (os.path.splitext(archive_name)[0]).endswith(".tar")
184 |
185 | # Now try to upload the pre-collected archive
186 | upload_result = insights_client.run(
187 | f"--payload={archive_name}", f"--content-type={compressor}"
188 | )
189 | assert "Uploading Insights data." in upload_result.stdout
190 | assert "Successfully uploaded report" in upload_result.stdout
191 |
192 |
193 | @pytest.mark.tier1
194 | def test_retries(insights_client):
195 | """
196 | :id: dafeb86e-463e-42fd-88e5-4551f1ba8f66
197 | :title: Test Retries on Upload Failure
198 | :description:
199 | This test verifies that client tries to upload archive if upload
200 | fails. Setting retries to 2 only because between each attempt the wait time is
201 | 180 sec. Set wrong base_url in insights-client.config to fail upload operation
202 | :tags: Tier 1
203 | :steps:
204 | 1. Register insights-client
205 | 2. Save the archive
206 | 3. Modify the configuration to use a non-existent base URL
207 | 4. Run insights-client with --payload option specifying --retry=2
208 | to attempt upload twice
209 | 5. verify the retry mechanism
210 | 6. verify the final failure message
211 | :expectedresults:
212 | 1. Insights-client is registered
213 | 2. Archive is saved
214 | 3. The configuration is modified and saved
215 | 4. The command is run
216 | 5. Each of the retry failed with expected error message
217 | 6. the final error message is as expected
218 | """
219 | reg_result = insights_client.run("--register", "--keep-archive")
220 | assert conftest.loop_until(lambda: insights_client.is_registered)
221 |
222 | # Save the archive, to be used while upload operation
223 | archive_name = reg_result.stdout.split()[-1]
224 |
225 | # Modifying config to break connection
226 | insights_client.config.auto_config = False
227 | insights_client.config.base_url = "non-existent-url.redhat.com"
228 | insights_client.config.save()
229 |
230 | # Now try to upload the pre-collected archive with retry=2 , default content=type gz
231 | upload_result = insights_client.run(
232 | f"--payload={archive_name}", "--content-type={gz}", "--retry=2", check=False
233 | )
234 |
235 | assert "Upload attempt 1 of 2 failed" in upload_result.stdout
236 | assert "Upload attempt 2 of 2 failed" in upload_result.stdout
237 | assert "Waiting 180 seconds then retrying" in upload_result.stdout
238 | assert "All attempts to upload have failed!" in upload_result.stdout
239 |
240 |
241 | @pytest.mark.tier1
242 | def test_retries_not_happening_on_unrecoverable_errors(insights_client):
243 | """
244 | :id: 1d740d1c-e98b-4571-86ac-10a233ff65ce
245 | :title: Test No Retries on Uncoverable Errors
246 | :description:
247 | This test verifies that client retries won't happen during
248 | unrecoverable errors. The client should try to upload just once and then fail.
249 | :tags: Tier 1
250 | :steps:
251 | 1. Register insights-client
252 | 2. Save the archive
253 | 3. Run insights-client with --payload option specifying invalid --content-type
254 | 4. Verify the output of the command
255 | 5. Verify no-retries occur
256 | :expectedresults:
257 | 1. Insights-client is registered
258 | 2. Archive is saved
259 | 3. The command is run
260 | 4. The process fails with an appropriate message
261 | 5. No retries occurred
262 | """
263 | reg_result = insights_client.run("--register", "--keep-archive")
264 | assert conftest.loop_until(lambda: insights_client.is_registered)
265 |
266 | # Save the archive, to be used while upload operation
267 | archive_name = reg_result.stdout.split()[-1]
268 |
269 | # Pass invalid content type to mock unrecoverable errors
270 | upload_result = insights_client.run(
271 | f"--payload={archive_name}",
272 | "--content-type=invalid-type",
273 | "--retry=2",
274 | check=False,
275 | )
276 | assert "Upload failed." in upload_result.stdout
277 | assert "Upload attempt 1 of 2 failed" not in upload_result.stdout
278 |
--------------------------------------------------------------------------------
/integration-tests/test_version.py:
--------------------------------------------------------------------------------
1 | """
2 | :casecomponent: insights-client
3 | :requirement: RHSS-291297
4 | :polarion-project-id: RHELSS
5 | :polarion-include-skipped: false
6 | :polarion-lookup-method: id
7 | :subsystemteam: rhel-sst-csi-client-tools
8 | :caseautomation: Automated
9 | :upstream: Yes
10 | """
11 |
12 | import pytest
13 |
14 |
15 | @pytest.mark.tier1
16 | def test_version(insights_client):
17 | """
18 | :id: 7ec671cb-39ae-4cda-b279-f05d7c835d5d
19 | :title: Test --version outputs client and core versions
20 | :description:
21 | This test verifies that running `insights-client --version` outputs
22 | both the client and core version information
23 | :tags: Tier 1
24 | :steps:
25 | 1. Run `insights-client --version`
26 | 2. Check the output for "Client: " and "Core: "
27 | :expectedresults:
28 | 1. Command executes without errors
29 | 2. Both "Client: " and "Core: " are present in the output
30 | """
31 | proc = insights_client.run("--version")
32 | assert "Client: " in proc.stdout
33 | assert "Core: " in proc.stdout
34 |
--------------------------------------------------------------------------------
/integration-tests/testimony.yml:
--------------------------------------------------------------------------------
1 | ---
2 | Id:
3 | casesensitive: false
4 | required: true
5 | type: string
6 | Polarion-Project-Id:
7 | casesensitive: false
8 | required: true
9 | type: choice
10 | choices:
11 | - RHELSS
12 | Polarion-Include-Skipped:
13 | casesensitive: false
14 | required: true
15 | type: string
16 | Polarion-Lookup-Method:
17 | casesensitive: false
18 | required: true
19 | type: string
20 | Reference:
21 | casesensitive: false
22 | required: false
23 | type: string
24 | CaseComponent:
25 | casesensitive: false
26 | required: true
27 | type: string
28 | Requirement:
29 | casesensitive: false
30 | required: true
31 | type: choice
32 | choices:
33 | - RHSS-291297
34 | SubSystemTeam:
35 | casesensitive: false
36 | required: true
37 | type: choice
38 | choices:
39 | - rhel-sst-csi-client-tools
40 | Parametrized:
41 | casesensitive: false
42 | required: false
43 | type: string
44 | CaseAutomation:
45 | casesensitive: false
46 | required: true
47 | type: string
48 | Upstream:
49 | casesensitive: false
50 | type: string
51 | Title:
52 | casesensitive: false
53 | type: string
54 | Description:
55 | casesensitive: false
56 | required: true
57 | type: string
58 | Tags:
59 | casesensitive: true
60 | required: true
61 | type: choice
62 | choices:
63 | - Tier 1
64 | - Tier 2
65 | - Tier 3
66 | Steps: {}
67 | ExpectedResults: {}
68 |
--------------------------------------------------------------------------------
/meson.build:
--------------------------------------------------------------------------------
1 | project('insights-client',
2 | version: '3.10.1',
3 | meson_version: '>=0.49'
4 | )
5 |
6 | python = import('python')
7 |
8 | python_installation = python.find_installation(get_option('python'))
9 |
10 | python_exec = '/usr/bin/python3'
11 |
12 | systemd = dependency('systemd', version: '>=231')
13 |
14 | config_data = configuration_data({
15 | 'bindir': get_option('prefix') / get_option('bindir'),
16 | 'BINDIR': get_option('prefix') / get_option('bindir'),
17 | 'DATADIR': get_option('prefix') / get_option('datadir'),
18 | 'DATAROOTDIR':get_option('prefix') / get_option('datadir'),
19 | 'DOCDIR': get_option('prefix') / get_option('datadir') / 'doc' / meson.project_name(),
20 | 'LIBEXECDIR': get_option('prefix') / get_option('libexecdir'),
21 | 'LOCALSTATEDIR': get_option('localstatedir'),
22 | 'PACKAGE': meson.project_name(),
23 | 'PACKAGE_VERSION': meson.project_version(),
24 | 'pkgsysconfdir': '/' / get_option('sysconfdir') / meson.project_name(),
25 | 'PREFIX': get_option('prefix'),
26 | 'PYTHON': python_exec,
27 | 'pythondir': python_installation.get_install_dir(),
28 | 'SBINDIR': get_option('prefix') / get_option('sbindir'),
29 | 'SYSCONFDIR': '/' / get_option('sysconfdir'),
30 | 'sysconfdir': '/' / get_option('sysconfdir'),
31 | 'top_srcdir': meson.source_root(),
32 | 'CORE_SELINUX_POLICY': get_option('core_selinux_policy'),
33 | })
34 |
35 | run_target('update-egg', command: 'scripts/01-upgrade-egg.sh')
36 |
37 | subdir('data')
38 | subdir('docs')
39 | subdir('src')
40 |
41 | configuration = '**Configuration**\n'
42 | configuration += '\tpython\t\t\t: ' + get_option('python') + '\n'
43 | if get_option('checkin').enabled()
44 | configuration += '\tcheckin\t: ' + 'enabled' + '\n'
45 | else
46 | configuration += '\tcheckin\t: ' + 'disabled' + '\n'
47 | endif
48 | if get_option('auto_registration').enabled()
49 | configuration += '\tauto_registration\t: ' + 'enabled' + '\n'
50 | else
51 | configuration += '\tauto_registration\t: ' + 'disabled' + '\n'
52 | endif
53 | if get_option('core_selinux_policy') != ''
54 | configuration += '\tSELinux policy for insights-core\t: ' + get_option('core_selinux_policy') + '\n'
55 | else
56 | configuration += '\tSELinux policy for insights-core\t: ' + 'disabled' + '\n'
57 | endif
58 | message(configuration)
59 |
--------------------------------------------------------------------------------
/meson_options.txt:
--------------------------------------------------------------------------------
1 | option('python', type: 'string', value: 'python3', description: 'python interpreter to use when finding python installation')
2 | option('auto_registration', type: 'feature', value: 'disabled', description: 'enable automatic registration')
3 | option('checkin', type: 'feature', value: 'disabled', description: 'enable hourly check-in')
4 | option('redhat_access_insights', type: 'boolean', value: false, description: 'enable deprecated redhat-access-insights executable')
5 | option('core_selinux_policy', type: 'string', value: '', description: 'SELinux policy for insights-core (empty: none used)')
6 |
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [tool.black]
2 | include = '(\.py(\.in)?|src/insights-client.in)$'
3 |
--------------------------------------------------------------------------------
/pytest.ini:
--------------------------------------------------------------------------------
1 | [pytest]
2 | markers =
3 | tier1: Mark a test to be Tier 1
4 | tier2: Mark a test to be Tier 2
5 | tier3: Mark a test to be Tier 3
6 |
--------------------------------------------------------------------------------
/requirements-dev.txt:
--------------------------------------------------------------------------------
1 | # the version of black is specified also in the stylish.yml github workflow;
2 | # please update the version there in case it is bumped here
3 | black==24.3.0
4 | flake8
5 |
--------------------------------------------------------------------------------
/scripts/01-upgrade-egg.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -xe
4 |
5 | cd "${MESON_SOURCE_ROOT}"
6 |
7 | declare -a PROGRAMS
8 | PROGRAMS+=(
9 | curl
10 | )
11 |
12 | for PROGRAM in "${PROGRAMS[@]}"; do
13 | if ! which "${PROGRAM}"; then
14 | echo "missing required program: ${PROGRAM}"
15 | exit 1
16 | fi
17 | done
18 |
19 | TAG=$(cat EGG_VERSION)
20 |
21 | curl --fail -L https://console.redhat.com/api/v1/static/release/insights-core.el10.egg --output data/rpm.egg
22 | curl --fail -L https://console.redhat.com/api/v1/static/release/insights-core.el10.egg.asc --output data/rpm.egg.asc
23 |
--------------------------------------------------------------------------------
/scripts/README.md:
--------------------------------------------------------------------------------
1 | ## 01-upgrade-egg.sh
2 |
3 | This script downloads the egg and the uploader.json (and the ones that are signed) that is defined in `EGG_VERSION` file.
--------------------------------------------------------------------------------
/src/insights-client.in:
--------------------------------------------------------------------------------
1 | #!@PYTHON@
2 |
3 | import sys
4 |
5 | from insights_client import _main
6 |
7 | sys.path.insert(1, "@pythondir@")
8 |
9 |
10 | if __name__ == "__main__":
11 | _main()
12 |
--------------------------------------------------------------------------------
/src/insights_client/constants.py.in:
--------------------------------------------------------------------------------
1 | """
2 | Constants
3 | """
4 |
5 | APP_NAME = "@PACKAGE@"
6 | VERSION = "@PACKAGE_VERSION@"
7 | PREFIX = "@PREFIX@"
8 | BINDIR = "@BINDIR@"
9 | SBINDIR = "@SBINDIR@"
10 | LIBEXECDIR = "@LIBEXECDIR@"
11 | DATAROOTDIR = "@DATAROOTDIR@"
12 | DATADIR = "@DATADIR@"
13 | SYSCONFDIR = "@SYSCONFDIR@"
14 | LOCALSTATEDIR = "@LOCALSTATEDIR@"
15 | DOCDIR = "@DOCDIR@"
16 | CORE_SELINUX_POLICY = "@CORE_SELINUX_POLICY@"
17 |
18 |
19 | class InsightsConstants(object):
20 | app_name = APP_NAME
21 | version = VERSION
22 |
--------------------------------------------------------------------------------
/src/insights_client/meson.build:
--------------------------------------------------------------------------------
1 | insights_client_sources = [
2 | '__init__.py',
3 | 'run.py',
4 | 'utc.py'
5 | ]
6 |
7 | insights_client_sources += configure_file(
8 | input: 'constants.py.in',
9 | output: '@BASENAME@',
10 | configuration: config_data
11 | )
12 |
13 | python_installation.install_sources(insights_client_sources, subdir: 'insights_client')
14 |
15 | subdir('tests')
16 |
--------------------------------------------------------------------------------
/src/insights_client/run.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 |
4 | import logging
5 |
6 | logger = logging.getLogger(__name__)
7 |
8 | try:
9 | try:
10 | from insights.client.phase import v1 as client
11 | except ImportError as e:
12 | sys.exit(
13 | "Error importing insights.client for %s as %s: %s"
14 | % (os.environ["INSIGHTS_PHASE"], os.environ["PYTHONPATH"], e)
15 | )
16 |
17 | phase = getattr(client, os.environ["INSIGHTS_PHASE"])
18 | sys.exit(phase())
19 | except KeyboardInterrupt:
20 | sys.exit(1)
21 | except Exception as e:
22 | print("Fatal: {0}".format(e))
23 | sys.exit(1)
24 |
--------------------------------------------------------------------------------
/src/insights_client/tests/conftest.py:
--------------------------------------------------------------------------------
1 | import os
2 | import pathlib
3 | import sys
4 |
5 |
6 | def pytest_configure(config):
7 | repo_root = pathlib.Path(__file__).parents[3]
8 |
9 | # Hijack sys.path, so we don't have to use 'PYTHONPATH=src/'
10 | sources: pathlib.Path = repo_root / "src"
11 | sys.path.insert(0, str(sources))
12 |
13 | # Point us to the RPM egg, if it hasn't been specified outside
14 | if "EGG" not in os.environ:
15 | os.environ["EGG"] = str((repo_root / "data" / "rpm.egg").resolve())
16 |
17 | # We have to push the EGG into PATH immediately.
18 | # It would have been done by the client on its own, but we need to mock out
19 | # some of the internal functions (see `test_client.py`), and for that we need
20 | # the egg to already be present.
21 | sys.path.insert(0, os.environ["EGG"])
22 |
23 | # Move the temporary directories outside /var/lib/insights/.
24 | import insights_client
25 |
26 | insights_client.TEMPORARY_GPG_HOME_PARENT_DIRECTORY = "/tmp/"
27 | # Point to the actual key we ship to be able to actually verify the bundled egg.
28 | insights_client.GPG_KEY = str(
29 | (repo_root / "data" / "redhattools.pub.gpg").resolve()
30 | )
31 |
--------------------------------------------------------------------------------
/src/insights_client/tests/meson.build:
--------------------------------------------------------------------------------
1 | pytest = find_program('pytest', 'pytest-3')
2 |
3 | env = environment()
4 | env.append('PYTHONPATH', meson.source_root() / 'src', meson.source_root() / 'data' / 'rpm.egg')
5 |
6 | test_sources = files('test_client.py', 'test_commands.py', 'test_sed.py')
7 |
8 | test('test',
9 | pytest,
10 | args: test_sources,
11 | env: env
12 | )
13 |
--------------------------------------------------------------------------------
/src/insights_client/tests/requirements-core.txt:
--------------------------------------------------------------------------------
1 | pyyaml
2 | requests
3 | setuptools
4 | six
5 |
--------------------------------------------------------------------------------
/src/insights_client/tests/requirements.txt:
--------------------------------------------------------------------------------
1 | pytest
2 | # Setuptools is required because we still rely on 'distutils' which have been dropped in Python 3.12.
3 | # setuptools package ships it vendorized as a top-level package, so for a time being we can rely on it.
4 | setuptools
5 | -r requirements-core.txt
6 |
--------------------------------------------------------------------------------
/src/insights_client/tests/test_client.py:
--------------------------------------------------------------------------------
1 | from unittest import mock
2 | import insights_client
3 | import pytest
4 |
5 |
6 | # Test config load error
7 | @mock.patch("os.getuid", return_value=0)
8 | @mock.patch(
9 | "insights.client.InsightsConfig.load_all", side_effect=ValueError("mocked error")
10 | )
11 | def test_load_config_error(os_uid, insightsConfig):
12 | with pytest.raises(SystemExit) as sys_exit:
13 | insights_client._main()
14 | assert sys_exit.value.code != 0
15 |
16 |
17 | # test keyboardinterrupt handler
18 | @mock.patch("os.getuid", return_value=0)
19 | @mock.patch("insights.client.InsightsConfig.load_all", side_effect=KeyboardInterrupt)
20 | def test_keyboard_interrupt(os_uid, client):
21 | with pytest.raises(SystemExit) as sys_exit:
22 | insights_client._main()
23 | assert sys_exit.value.code != 0
24 |
25 |
26 | # check run phase error 100 handler
27 | @mock.patch("os.getuid", return_value=0)
28 | @mock.patch("insights.client.phase.v1.get_phases")
29 | @mock.patch("insights.client.InsightsClient")
30 | @mock.patch("insights_client.subprocess.Popen")
31 | def test_phase_error_100(mock_subprocess, client, phase, _os_getuid):
32 | client.get_conf = mock.Mock(return_value={"gpg": False})
33 |
34 | with pytest.raises(SystemExit) as sys_exit:
35 | mock_subprocess.return_value.returncode = 100
36 | mock_subprocess.return_value.communicate.return_value = ("output", "error")
37 | insights_client.run_phase(phase, client, validated_eggs=[])
38 | assert sys_exit.value.code == 0
39 |
--------------------------------------------------------------------------------
/src/insights_client/tests/test_commands.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import insights_client
4 | from unittest.mock import patch
5 | from pytest import raises
6 |
7 |
8 | @patch("insights_client.sys.argv", ["insights-client", "--version"])
9 | @patch("insights_client._main")
10 | def test_version_command(capsys):
11 | with patch("os.getuid", return_value=0):
12 | insights_client._main()
13 | captured = capsys.readouterr()
14 | output_sudo = captured.out
15 | with patch("os.getuid", return_value=1):
16 | insights_client._main()
17 | captured = capsys.readouterr()
18 | output_normal = captured.out
19 |
20 | assert output_sudo == output_normal
21 |
22 |
23 | @patch("insights_client.sys.argv", ["insights-client", "--help"])
24 | @patch("insights_client._main")
25 | def test_help_command(capsys):
26 | with patch("os.getuid", return_value=0):
27 | insights_client._main()
28 | captured = capsys.readouterr()
29 | output_sudo = captured.out
30 | with patch("os.getuid", return_value=1):
31 | insights_client._main()
32 | captured = capsys.readouterr()
33 | output_normal = captured.out
34 |
35 | assert output_sudo == output_normal
36 |
37 |
38 | @patch("insights_client.sys.argv", ["insights-client"])
39 | def test_exit_when_run_phases_no_sudo():
40 | with raises(SystemExit) as pytest_wrapped_e:
41 | with patch("os.getuid", return_value=1):
42 | insights_client._main()
43 | assert pytest_wrapped_e.type == SystemExit
44 | assert pytest_wrapped_e.value.args[0] == "Insights client must be run as root."
45 |
--------------------------------------------------------------------------------
/src/insights_client/tests/test_motd.py:
--------------------------------------------------------------------------------
1 | import os
2 | import pathlib
3 | import tempfile
4 | import typing
5 | import unittest
6 | import unittest.mock
7 |
8 | import pytest
9 |
10 | import insights_client
11 |
12 |
13 | class MockFS:
14 | """Mock filesystem.
15 |
16 | Ensures that the files required for the MOTD manipulation are created
17 | in a temporary directory instead of working with actual system files.
18 | """
19 |
20 | _dir: tempfile.TemporaryDirectory
21 |
22 | @property
23 | def _chroot(self) -> pathlib.Path:
24 | return pathlib.Path(self._dir.name)
25 |
26 | def touch(self, path: str):
27 | (self._chroot / path).open("w").close()
28 |
29 | def exists(self, path: str) -> bool:
30 | return (self._chroot / path).exists()
31 |
32 | def symlink_to(self, path: str, point_to: str):
33 | (self._chroot / path).symlink_to(point_to)
34 |
35 | def samefile(self, first: str, second: str) -> bool:
36 | return (self._chroot / first).samefile(self._chroot / second)
37 |
38 | def __init__(self):
39 | self._dir = tempfile.TemporaryDirectory(prefix="test-chroot-")
40 |
41 | paths: typing.Dict[str, str] = {
42 | "insights_client.MOTD_SRC": "etc/insights-client/insights-client.motd",
43 | "insights_client.MOTD_FILE": "etc/motd.d/insights-client",
44 | "insights_client.REGISTERED_FILE": "etc/insights-client/.registered",
45 | "insights_client.UNREGISTERED_FILE": "etc/insights-client/.unregistered",
46 | }
47 |
48 | self.patches: typing.List[unittest.mock.patch] = []
49 | for target, path in paths.items():
50 | mocked_path = self._chroot / path
51 | mocked_path.parent.mkdir(parents=True, exist_ok=True)
52 | patch = unittest.mock.patch(target, f"{mocked_path!s}")
53 | self.patches.append(patch)
54 | patch.start()
55 |
56 | self.touch("etc/insights-client/insights-client.motd")
57 |
58 | def __del__(self):
59 | for patch in self.patches:
60 | patch.stop()
61 | self._dir.cleanup()
62 |
63 |
64 | @pytest.fixture(scope="function")
65 | def mock_fs():
66 | fs = MockFS()
67 | yield fs
68 | del fs
69 |
70 |
71 | def test_present(mock_fs):
72 | assert not mock_fs.exists("etc/motd.d/insights-client")
73 |
74 | # The file gets created/symlinked when .registered & .unregistered do not exist
75 | insights_client.update_motd_message()
76 | assert mock_fs.exists("etc/motd.d/insights-client")
77 | assert mock_fs.samefile(
78 | "etc/motd.d/insights-client", "etc/insights-client/insights-client.motd"
79 | )
80 |
81 |
82 | @pytest.mark.parametrize(
83 | "filename",
84 | [".registered", ".unregistered"],
85 | )
86 | def test_absent_on_dot(mock_fs, filename):
87 | # The MOTD gets created by default...
88 | insights_client.update_motd_message()
89 | assert mock_fs.exists("etc/motd.d/insights-client")
90 |
91 | # ...and gets removed when .registered/.unregistered exists.
92 | mock_fs.touch(f"etc/insights-client/{filename}")
93 |
94 | insights_client.update_motd_message()
95 | assert not mock_fs.exists("etc/motd.d/insights-client")
96 |
97 | # ...and it stays absent when run multiple times.
98 | insights_client.update_motd_message()
99 | assert not mock_fs.exists("etc/motd.d/insights-client")
100 |
101 |
102 | def test_ignored_on_dev_null(mock_fs):
103 | # When the /etc/motd.d/insights-client is a symbolic link to /dev/null...
104 | mock_fs.symlink_to("etc/motd.d/insights-client", os.devnull)
105 |
106 | # ...it should not be overwritten...
107 | insights_client.update_motd_message()
108 | assert mock_fs.samefile("etc/motd.d/insights-client", os.devnull)
109 |
110 | # ...whether the MOTD file should be present or not.
111 | mock_fs.touch("etc/insights-client/.registered")
112 | insights_client.update_motd_message()
113 | assert mock_fs.samefile("etc/motd.d/insights-client", os.devnull)
114 |
--------------------------------------------------------------------------------
/src/insights_client/tests/test_sed.py:
--------------------------------------------------------------------------------
1 | import pathlib
2 | import subprocess
3 |
4 | import pytest
5 |
6 |
7 | _REPO_ROOT = pathlib.Path(__file__).parents[3]
8 | SED_FILE: pathlib.Path = _REPO_ROOT / "data" / ".exp.sed"
9 |
10 |
11 | def run_sed(stdin: str) -> str:
12 | """Obfuscate input with `sed` script file."""
13 | process = subprocess.Popen(
14 | ["sed", "-rf", str(SED_FILE)],
15 | stdin=subprocess.PIPE,
16 | stdout=subprocess.PIPE,
17 | stderr=subprocess.PIPE,
18 | env={"LC_ALL": "C.UTF-8"},
19 | universal_newlines=True,
20 | )
21 | stdout, _ = process.communicate(input=stdin)
22 | return stdout
23 |
24 |
25 | @pytest.mark.parametrize(
26 | ["stdin", "obfuscated"],
27 | [
28 | ["password=root", "password=********"],
29 | ["password=p4ssw0rd", "password=********"],
30 | ["password=I!m_strong1S7arQ4ST$2bu/QurvRCjrTGWYajIMx/", "password=********"],
31 | ["password=!p@4#$$w%O^r&d*p(a)s-s_w+o=r/d", "password=********"],
32 | ["password_verification=root", "password_verification=********"],
33 | ["password == root", "password == ********"],
34 | ["password root", "password ********"],
35 | ["password --md555 4facade5cafe", "password --md555 ********"],
36 | ["password--md5 4facade5cafe", "password--md5 ********"],
37 | ["password--sha1", "password********"],
38 | [" (abc=def&password=root&key=value )", " (abc=def&password=******** )"],
39 | ["password: root", "password: ********"],
40 | ['{auth: {password: "root"}}', '{auth: {password: "********"}}'],
41 | ['', ''],
42 | ],
43 | )
44 | def test_fully_obfuscate(stdin, obfuscated):
45 | stdout = run_sed(stdin)
46 | assert stdout == obfuscated
47 |
48 |
49 | @pytest.mark.parametrize(
50 | ["stdin", "obfuscated"],
51 | [
52 | ["password=pass word", "password=******** word"],
53 | ["password=pass,word", "password=********,word"],
54 | ["password=pass.word", "password=********.word"],
55 | ["password=pass[word]", "password=********[word]"],
56 | ["password=pass{word}", "password=********{word}"],
57 | ["password=pass", "password=********"],
58 | ["password=pas/sw\\ord", "password=********\\ord"],
59 | ["password=passwörd", "password=********örd"],
60 | ["password=passw٥rd", "password=********٥rd"],
61 | ],
62 | )
63 | def test_partially_obfuscate(stdin, obfuscated):
64 | stdout = run_sed(stdin)
65 | assert stdout == obfuscated
66 |
67 |
68 | @pytest.mark.parametrize(
69 | ["stdin", "obfuscated"],
70 | [
71 | ["password ******** root", "password ******** ********"],
72 | ["password******** root", "password******** ********"],
73 | ],
74 | )
75 | def test_obfuscate_rest(stdin, obfuscated):
76 | stdout = run_sed(stdin)
77 | assert stdout == obfuscated
78 |
79 |
80 | @pytest.mark.parametrize(
81 | ["stdin", "obfuscated"],
82 | [
83 | ["password * root", "password ******** ********"],
84 | ["password*** root", "password******** ********"],
85 | ["password --sha1 4facade5cafe", "password ******** ********"],
86 | ["password--sha1 4facade5cafe", "password******** ********"],
87 | ],
88 | )
89 | def test_joint_obfuscation(stdin, obfuscated):
90 | stdout = run_sed(stdin)
91 | assert stdout == obfuscated
92 |
93 |
94 | @pytest.mark.parametrize(["stdin"], [["PermitRootLogin without-password"]])
95 | def test_no_obfuscation(stdin):
96 | stdout = run_sed(stdin)
97 | assert stdout == stdin
98 |
--------------------------------------------------------------------------------
/src/insights_client/utc.py:
--------------------------------------------------------------------------------
1 | import datetime
2 |
3 |
4 | class UTC(datetime.tzinfo):
5 | """
6 | UTC is a concrete subclass of datetime.tzinfo representing the UTC
7 | time zone.
8 | """
9 |
10 | def utcoffset(self, dt):
11 | return datetime.timedelta(0)
12 |
13 | def tzname(self, dt):
14 | return "UTC"
15 |
16 | def dst(self, dt):
17 | return datetime.timedelta(0)
18 |
19 |
20 | def make_utc_datetime_rfc3339():
21 | return (
22 | datetime.datetime.utcnow().replace(microsecond=0, tzinfo=UTC()).isoformat("T")
23 | )
24 |
--------------------------------------------------------------------------------
/src/meson.build:
--------------------------------------------------------------------------------
1 | insights_client_sources = [
2 | 'insights-client.in',
3 | ]
4 |
5 | if get_option('redhat_access_insights')
6 | insights_client_sources += 'redhat-access-insights.in'
7 | endif
8 |
9 | foreach source : insights_client_sources
10 | configure_file(
11 | input: source,
12 | output: '@BASENAME@',
13 | configuration: config_data,
14 | install_dir: get_option('bindir'),
15 | install_mode: 'rwxr-xr-x'
16 | )
17 | endforeach
18 |
19 | subdir('insights_client')
20 |
--------------------------------------------------------------------------------
/src/redhat-access-insights.in:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | >&2 echo "WARNING: $(basename "$0") is deprecated and will be removed in a future release; use 'insights-client' instead."
4 | sleep 3
5 | exec @bindir@/insights-client "$@"
6 |
--------------------------------------------------------------------------------
/systemtest/copr-setup.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/bash -eux
2 | dnf install -y dnf-plugins-core
3 |
4 | #Determine the repo needed from copr
5 | #Available repositories: 'centos-stream-8-x86_64', 'rhel-8-x86_64',
6 | # 'centos-stream-9-x86_64', 'rhel-9-x86_64', 'fedora-40-x86_64',
7 | # 'fedora-39-x86_64', 'fedora-rawhide-x86_64'
8 | source /etc/os-release
9 | if [ "$ID" == "centos" ]; then
10 | ID='centos-stream'
11 | fi
12 | VERSION_MAJOR=$(echo ${VERSION_ID} | cut -d '.' -f 1)
13 | COPR_REPO="${ID}-${VERSION_MAJOR}-$(uname -m)"
14 |
15 | #get yggdrasil
16 | dnf copr -y enable @yggdrasil/latest ${COPR_REPO}
17 | dnf install -y yggdrasil yggdrasil-worker-package-manager --disablerepo=* --enablerepo=*yggdrasil*
18 |
19 | # These PR packit builds have an older version number for some reason than the released...
20 | dnf remove -y --noautoremove insights-client
21 | dnf copr -y enable packit/RedHatInsights-insights-client-${ghprbPullId} ${COPR_REPO}
22 | dnf install -y insights-client --disablerepo=* --enablerepo=*insights-client*
23 |
--------------------------------------------------------------------------------
/systemtest/guest-setup.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/bash
2 | # this is a general use version of the guest setup that happens in testing farm
3 |
4 | # check for insights-client from existing repos
5 | if ! dnf info insights-client &>/dev/null; then
6 | source <(cat /etc/os-release | grep ^ID)
7 |
8 | # convert os-release to copr name
9 | if [ "$ID" == "centos" ]; then
10 | DISTRO='centos-stream'
11 | else
12 | DISTRO="$ID"
13 | fi
14 |
15 | # have to pull from dnf as os-release does not follow the same format on rhel
16 | RELEASEVER=$(python3 -c 'import dnf, json; db = dnf.dnf.Base(); print(db.conf.substitutions["releasever"])')
17 |
18 | curl https://copr.fedorainfracloud.org/coprs/g/yggdrasil/latest/repo/$DISTRO-$RELEASEVER/group_yggdrasil-latest-$DISTRO-$RELEASEVER.repo \
19 | -o /etc/yum.repos.d/yggdrasil.repo
20 | fi
21 |
22 | dnf -y install insights-client
23 |
--------------------------------------------------------------------------------
/systemtest/insights-core-setup.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/bash -ux
2 |
3 | # Stolen from
4 | # https://github.com/RedHatInsights/insights-core/blob/master/insights/tests/client/test_crypto.py
5 | # https://gitlab.cee.redhat.com/mhorky/tasks/-/blob/main/CCT-131/steps.md#prepare-the-vm
6 |
7 | cat >public.armor.key << EOF
8 | -----BEGIN PGP PUBLIC KEY BLOCK-----
9 |
10 | mDMEZpbJQRYJKwYBBAHaRw8BAQdA3HBHO0ADUcKgqaTbj6BUU82ZbJ5ojhTdju7b
11 | 9+NGtEm0GkNDVCBRRSA8Y2N0LXFlQHJlZGhhdC5jb20+iJMEExYKADsWIQQbHWyM
12 | LBEKAqrK4N73Fp/8VshPuwUCZpbJQQIbAwULCQgHAgIiAgYVCgkICwIEFgIDAQIe
13 | BwIXgAAKCRD3Fp/8VshPu3qhAQDWOV+kGpIGdLBRqIuQZCFAH5rS/6HW7J16CuS5
14 | qub0ZgEAvSiIanOj1TaGHnYOyHXi0694Amfvr3Txzligo62OwwW4OARmlslBEgor
15 | BgEEAZdVAQUBAQdAbCvp9o2XYSmtQweCmRBKcYUUPfzkoENeB+AehOxiMl0DAQgH
16 | iHgEGBYKACAWIQQbHWyMLBEKAqrK4N73Fp/8VshPuwUCZpbJQQIbDAAKCRD3Fp/8
17 | VshPu+vWAQCW0w/EIsPMPnlecizvNf3pXydze5XotIr4XFrJaB465AD8CVn5JDN2
18 | 5lg1O5u16Ww3WAaT01FCealgq+NnG/03IAI=
19 | =xnEk
20 | -----END PGP PUBLIC KEY BLOCK-----
21 | EOF
22 |
23 | cat >private.armor.key << EOF
24 | -----BEGIN PGP PRIVATE KEY BLOCK-----
25 |
26 | lFgEZpbJQRYJKwYBBAHaRw8BAQdA3HBHO0ADUcKgqaTbj6BUU82ZbJ5ojhTdju7b
27 | 9+NGtEkAAQDKnXHYfXWHpRQiNTPU8mqVcOg3M7VlZPxMgcEJH4bi2BBktBpDQ1Qg
28 | UUUgPGNjdC1xZUByZWRoYXQuY29tPoiTBBMWCgA7FiEEGx1sjCwRCgKqyuDe9xaf
29 | /FbIT7sFAmaWyUECGwMFCwkIBwICIgIGFQoJCAsCBBYCAwECHgcCF4AACgkQ9xaf
30 | /FbIT7t6oQEA1jlfpBqSBnSwUaiLkGQhQB+a0v+h1uydegrkuarm9GYBAL0oiGpz
31 | o9U2hh52Dsh14tOveAJn76908c5YoKOtjsMFnF0EZpbJQRIKKwYBBAGXVQEFAQEH
32 | QGwr6faNl2EprUMHgpkQSnGFFD385KBDXgfgHoTsYjJdAwEIBwAA/0lTtr1yPIFe
33 | +3xHwOEaA9K3Iss8unb7v8jAPTIUnRoYEI2IeAQYFgoAIBYhBBsdbIwsEQoCqsrg
34 | 3vcWn/xWyE+7BQJmlslBAhsMAAoJEPcWn/xWyE+769YBAJbTD8Qiw8w+eV5yLO81
35 | /elfJ3N7lei0ivhcWsloHjrkAPwJWfkkM3bmWDU7m7XpbDdYBpPTUUJ5qWCr42cb
36 | /TcgAg==
37 | =YrcZ
38 | -----END PGP PRIVATE KEY BLOCK-----
39 | EOF
40 |
41 | gpg --import public.armor.key
42 | gpg --import private.armor.key
43 | KEYID=$(gpg --list-secret-keys --keyid-format long cct-qe \
44 | | grep sec | awk '{ split($2, a, "/"); print a[2] }')
45 | gpg --output public.gpg --export $KEYID
46 |
47 | mv /etc/insights-client/redhattools.pub.gpg{,.original}
48 | mv ./public.gpg /etc/insights-client/redhattools.pub.gpg.dev
49 | mkdir temp && chmod 700 temp
50 | gpg --homedir temp --import /etc/insights-client/redhattools.pub.gpg.*
51 | gpg --homedir temp --export > /etc/insights-client/redhattools.pub.gpg
52 | rm -rf temp/
53 |
54 | mv /etc/insights-client/rpm.egg{,.original}
55 | mv /etc/insights-client/rpm.egg.asc{,.original}
56 |
57 | currDir=$PWD
58 | cd ~/
59 | git clone https://github.com/RedHatInsights/insights-core.git
60 | cd insights-core
61 | git switch $insightsCoreBranch
62 |
63 | # Overwrite version and release of Core, to ensure we're always newer than released versions
64 | sed -i "s/3.0.8/9.99.999/" insights/VERSION
65 | sed -i "s/dev/0/" insights/RELEASE
66 |
67 | ./build_client_egg.sh
68 | cp insights.zip last_stable.egg
69 | gpg --detach-sign -u $KEYID --armor last_stable.egg
70 | cp last_stable.egg last_stable.egg.asc /var/lib/insights/
71 |
72 | sed -ie 's/#auto_update=True/auto_update=False/g' \
73 | /etc/insights-client/insights-client.conf
74 |
75 | cd $currDir
76 |
--------------------------------------------------------------------------------
/systemtest/plans/main.fmf:
--------------------------------------------------------------------------------
1 | summary: insights-client test suite
2 | discover:
3 | how: fmf
4 |
5 | execute:
6 | how: tmt
7 |
--------------------------------------------------------------------------------
/systemtest/tests/integration/main.fmf:
--------------------------------------------------------------------------------
1 | summary: Runs tmt tests
2 | test: ./test.sh
3 | duration: 3h
4 |
--------------------------------------------------------------------------------
/systemtest/tests/integration/test.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -u
3 | set -x
4 |
5 | # get to project root
6 | cd ../../../
7 |
8 | # Check for bootc/image-mode deployments which should not run dnf
9 | if ! command -v bootc >/dev/null || bootc status | grep -q 'type: null'; then
10 | # Check for GitHub pull request ID and install build if needed.
11 | # This is for the downstream PR jobs.
12 | [ -z "${ghprbPullId+x}" ] || ./systemtest/copr-setup.sh
13 |
14 | # Simulate the packit setup on downstream builds.
15 | # This is for ad-hoc and compose testing.
16 | rpm -q insights-client || ./systemtest/guest-setup.sh
17 |
18 | dnf --setopt install_weak_deps=False install -y \
19 | podman git-core python3-pip python3-pytest logrotate bzip2 zip \
20 | scap-security-guide openscap-scanner openscap bzip2-devel
21 | fi
22 |
23 | # If this is an insightsCore PR build and sign the new egg.
24 | [ -z "${insightsCoreBranch+x}" ] || ./systemtest/insights-core-setup.sh
25 |
26 | # Override settings if provided and available.
27 | if [ -n "${SETTINGS_URL+x}" ] && curl -I "$SETTINGS_URL" > /dev/null 2>&1; then
28 | [ -f ./settings.toml ] && mv ./settings.toml.bak
29 | curl "$SETTINGS_URL" -o ./settings.toml
30 | fi
31 |
32 | python3 -m venv venv
33 | # shellcheck disable=SC1091
34 | . venv/bin/activate
35 |
36 | pip install -r integration-tests/requirements.txt
37 |
38 | pytest --log-level debug --junit-xml=./junit.xml -v integration-tests
39 | retval=$?
40 |
41 | if [ -d "$TMT_PLAN_DATA" ]; then
42 | cp ./junit.xml "$TMT_PLAN_DATA/junit.xml"
43 | cp -r ./artifacts "$TMT_PLAN_DATA/"
44 | fi
45 |
46 | exit $retval
47 |
--------------------------------------------------------------------------------