Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 6 additions & 16 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,9 @@ jobs:
uses: actions/setup-python@v5
with:
python-version: "3.14"
- name: Install python tools
run: pipx install flake8 pyright black pyflakes pytest cfbs cfengine
- name: Check the status with cfbs
run: cfbs status
- name: Validate with cfbs
run: cfbs validate
- name: Check the formatting
run: cfbs --check pretty ./cfbs.json
- name: Linting python code
run: ./ci/linting.sh
- name: Run promise type tests
run: pytest promise-types/ -v
- name: Lint policy with CFEngine CLI
run: cfengine lint --strict no ./
- name: Check formatting with CFEngine CLI
run: cfengine format --check
- name: Install CFEngine community for tests
run: |
pipx install cf-remote
cf-remote install --clients localhost --edition community
- name: Run make check for linting, formatting and tests
run: make check
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,5 @@ node_modules/
build/
dist/
.cache
tests/deploy/cfbs.json
tests/deploy/out
25 changes: 25 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
.PHONY: check lint format all clean tools

all: tools clean lint format check

tools:
sudo pipx install --global flake8 pyright black pyflakes pytest cfbs cfengine
echo "deploy test requires cf-agent installed..."
command -v cf-agent

clean:
rm -rf tests/deploy/out

lint: clean tools
cfbs status
cfbs validate
cfbs --check pretty ./cfbs.json
./ci/linting.sh
cfengine lint --strict no ./

format: lint
cfengine format --check

check: format
pytest promise-types/ -v
bash tests/deploy/test.sh
25 changes: 22 additions & 3 deletions cfbs.json
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@
},
"delete-home-dotshosts": {
"description": "Ensure that ~/.shosts files are not present, as they present a security risk.",
"subdirectory": "security/delete-home-dotshots",
"subdirectory": "security/delete-home-dotshosts",
"steps": [
"copy policy/main.cf services/cfbs/delete-home-dotshots/",
"policy_files services/cfbs/delete-home-dotshots/",
Expand Down Expand Up @@ -497,10 +497,10 @@
"description": "Allows you to specify a list of packages you want uninstalled on your hosts.",
"subdirectory": "security/uninstall-packages",
"steps": [
"copy uninstall-packages.cf services/cfbs/modules/uninstall-packages/uninstall-packages.cf",
"copy main.cf services/cfbs/modules/uninstall-packages/main.cf",
"input uninstall-packages/input.json def.json",
"bundles uninstall_packages:uninstall_packages",
"policy_files services/cfbs/modules/uninstall-packages/uninstall-packages.cf"
"policy_files services/cfbs/modules/uninstall-packages/main.cf"
],
"input": [
{
Expand Down Expand Up @@ -546,6 +546,25 @@
"bundles windows_capability"
]
},
"install-pipx": {
"description": "Optionally install pipx.",
"subdirectory": "software",
"steps": [
"copy install-pipx.cf services/cfbs/software/install-pipx.cf",
"policy_files services/cfbs/software/install-pipx.cf",
"bundles install_pipx"
]
},
"install-ansible": {
"description": "Optionally install ansible.",
"subdirectory": "software",
"steps": [
"copy install-ansible.cf services/cfbs/software/install-ansible.cf",
"policy_files services/cfbs/software/install-ansible.cf",
"bundles install_ansible"
],
"dependencies": ["install-pipx"]
},
"windows-openssh-server": {
"description": "Optionally install Windows OpenSSH Server.",
"subdirectory": "software/windows",
Expand Down
4 changes: 2 additions & 2 deletions inventory/inventory-smartctl/policy.cf
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ bundle agent main
"_sdir" string => "$(sys.statedir)";
"_cache_ttl" string => "3600";

# 1 hour
# 1 hour

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is 1 hour?

linux._have_smartctl::

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably could just be _have_smartctl::

# Enumerate drives - extract first field from each line of smartctl --scan
"_scan_lines"
slist => splitstring(
Expand All @@ -52,7 +53,6 @@ bundle agent main
"_cache[${_drives}]"
string => "$(_sdir)/inventory_smartctl_${_id[${_drives}]}.json";

linux._have_smartctl::
# Rolled-up status: OK or DEGRADED (SMARTCTL_MISSING when smartctl absent)
"smartctl_status"
string => "DEGRADED",
Expand Down
61 changes: 61 additions & 0 deletions software/install-ansible.cf
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Steps here based on this guide: https://docs.ansible.com/projects/ansible/latest/installation_guide/intro_installation.html
#
# host specific data supported, in the data bundle context
#
# ansible_installed: class, if defined, installed ansible

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

below you are keying off of data:install_ansible I would specify it the same here. When I see a class without a namespace, I assume the class is expected to be in the default namespace.

# ansible_minimal_install: class, if defined, minimal install aka ansible-core
# ansible_full_install: class, if defined, full install. This is the default if neither minimal or full classes are defined.
Comment on lines +6 to +7

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same, I would call out the namespace explicitly here.

bundle agent install_ansible
{
methods:
linux.data:install_ansible::
"install_ansible_main";

reports:
windows::
"Use WSL to install Ansible on Windows. See https://blog.rolpdog.com/2020/03/why-no-ansible-controller-for-windows.html";

!linux::
"Installing Ansible on a non-Linux host is not currently supported";
Comment on lines +15 to +19

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe swap the order so that the reports come out saying installing ansible on non liux isnt supported and then emits the instruction for installing on windows.

}

bundle agent install_ansible_main
{
classes:
"ansible_installed"
expression => returnszero("command -v ansible >/dev/null", "useshell");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Humm, my instinct would be to use something like isgreaterthan(length(packagematching()))

I guess you should guard this classes promise with linux:: to avoid the attempt on non-linux (pre-eval).

Woudlnt it be nice to have a "default context" for a file or bundle where you could set the default context here to linux?


vars:
"install_ansible_command"
string => "${base_command}==${data:install_ansible.version}",
if => isvariable("data:install_ansible.version");

"install_ansible_command"
string => "${base_command}",
if => not(isvariable("data:install_ansible.version"));

data:ansible_minimal_install::
"base_command" string => "pipx install --global ansible-core";

data:ansible_full_install|(!data:ansible_full_install.!data:ansible_minimal_install)::
"base_command" string => "pipx install --global --include-deps ansible";
Comment on lines +29 to +41

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ifelse() might read more nicely.


methods:
"install_pipx_main" classes => if_ok("pipx_installed");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not a fan of the if_ok classes body it sort of papers over repaired saying it's totally ok, but sometimes you can repair and still not be ok (semantic nitpic). this one doesn't need guarding because it wont trigger in pre-eval.


commands:
pipx_installed.!ansible_installed::
"${install_ansible_command}"
contain => in_shell_umask(022),
comment => "The default umask of 077 would create /opt/pipx/venvs/ansible which is inaccessible to everyone but root, so use 022 instead.";
Comment on lines +47 to +50

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess the old pip package methods don't work well for this?


reports:
ansible_installed::
"ansible_installed";
Comment on lines +52 to +54

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would delete this report before shipping.

}

body contain in_shell_umask(umask)
{
useshell => "true";
umask => "${umask}";
}
34 changes: 34 additions & 0 deletions software/install-pipx.cf
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
bundle agent install_pipx
{
methods:
linux.data:install_pipx::
"install_pipx_main";

reports:
windows::
"Use WSL to install software";

!linux::
"Installing Ansible on a non-Linux host is not currently supported";
Comment on lines +8 to +12

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe reverse the order of reports so it says not supported and then tells how to install on windows?

}

bundle agent install_pipx_main
{
classes:
"pipx_installed"
expression => returnszero("command -v pipx >/dev/null", "useshell");
Comment on lines +18 to +19

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Guard this on linux:: to avoid execution on non-linux cause pre-eval


packages:
"pipx" classes => if_ok("pipx_package_ok");

files:
pipx_installed|pipx_package_ok::
"/opt/pipx"
perms => mog("755", "root", "root"),
comment => "/opt/pipx in some cases will be 700 which prevents non-root users from running installed commands.";

"/opt/pipx/venvs"
perms => mog("755", "root", "root"),
depth_search => recurse_with_base("1"),
comment => "/opt/pipx/venvs in some cases will be 700 which prevents non-root users from running installed commands.";

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious about those cases. Is that specific platform?

}
9 changes: 9 additions & 0 deletions tests/deploy/00-promise-run-no-errors.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/usr/bin/env bash
# assumes deploy.sh has already run adjacent to this file

set -ex
sudo cf-agent -KI > log
if grep 'error:' log; then
grep 'error:' log
exit 1
fi
20 changes: 20 additions & 0 deletions tests/deploy/01-install-ansible-full-test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/usr/bin/env bash
# assumes deploy.sh has already run adjacent to this file

set -ex

sudo pipx uninstall --global ansible || true
sudo pipx uninstall --global ansible-core || true

sudo cf-agent -Kd -Ddata:install_ansible -Ddata:ansible_full_install --bundle install_ansible > log
if grep 'error:' log; then
grep 'error:' log
exit 1
fi

ansible --version
echo "expect that ansible-core is not installed via pipx list"
if ( sudo pipx list --global --short | grep ansible-core ); then
echo "expected only ansible to be installed, but found ansible-core"
exit 1
fi
16 changes: 16 additions & 0 deletions tests/deploy/02-install-ansible-minimal-test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/usr/bin/env bash
set -ex

sudo pipx uninstall --global ansible || true
sudo pipx uninstall --global ansible-core || true

sudo cf-agent -Kd -Ddata:install_ansible -Ddata:ansible_minimal_install --bundle install_ansible > log
if grep 'error:' log; then
grep 'error:' log
exit 1
fi

ansible --version
if ! ( sudo pipx list --global --short | grep ansible-core ); then
echo "expected ansible-core to be installed but did not find that in pipx list output"
fi
55 changes: 55 additions & 0 deletions tests/deploy/03-install-ansible-versions-test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#!/usr/bin/env bash
set -ex

sudo pipx uninstall --global ansible || true
sudo pipx uninstall --global ansible-core || true

function cleanup
{
sudo rm -f /var/cfengine/data/host_specific.json || true # to make sure any version data is removed for other tests other runs
}

trap cleanup EXIT

good_version="2.21.3"

sudo mkdir -p /var/cfengine/data
cat <<EOF | sudo tee /var/cfengine/data/host_specific.json
{
"vars": {
"data:install_ansible.version": "$good_version"
}
}
EOF

sudo cf-agent -Kd -Ddata:install_ansible -Ddata:ansible_minimal_install --bundle install_ansible > log

if grep 'error:' log; then
grep 'error:' log
exit 1
fi

ansible --version | grep "${good_version}"

sudo pipx uninstall --global ansible || true
sudo pipx uninstall --global ansible-core || true

bad_version="x.y.z"
cat <<EOF | sudo tee /var/cfengine/data/host_specific.json
{
"vars": {
"data:install_ansible.version": "$bad_version"
}
}
EOF
echo "Evaluating install_ansible bundle expecting an error due to bad version value"
sudo cf-agent -Kd -Ddata:install_ansible -Ddata:ansible_minimal_install --bundle install_ansible > log

if grep 'error:' log; then
echo "Expected error found due to bad version value. Test passes."
grep 'error:' log
exit 0
fi

echo "Expected errors when installing ansible with bad version"
exit 1
39 changes: 39 additions & 0 deletions tests/deploy/deploy.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#!/usr/bin/env bash
set -ex

echo "WARNING/TODO: This test, $0, requires all changes to be pushed up to a branch in order to test the latest. This could be improved if cfbs add could work with the modules repo and a cfbs.json file. See ENT-14421"
if [ -n "$GITHUB_HEAD_REF" ]; then
# github case
BRANCH="$GITHUB_HEAD_REF"
else
# local case
BRANCH=$(git rev-parse --abbrev-ref HEAD)
fi

# workaround, if git@ url then we get Error: Cannot specify more than one version of the same module
# so transform the remote url
REPO=$(git remote get-url origin | \
sed -e 's,git@,https://,' \
-e 's,com:,com/,' \
)

if [ -n "$GITHUB_HEAD_REF" ]; then
REPO="$(echo "$REPO" | sed -e "s,cfengine,$GITHUB_TRIGGERING_ACTOR,")"
fi

thisdir="$(dirname "$0")"
cd "$thisdir"
[ -d .git ] && rm -rf .git
[ -f cfbs.json ] && rm cfbs.json
cfbs --version
cfbs init --non-interactive
cfbs --non-interactive add "$REPO@$BRANCH"
cfbs build
sudo cfbs install
sudo cf-agent -IB 127.0.0.1 > log

if grep 'error:' log; then
grep 'error:' log
exit 1
fi

9 changes: 9 additions & 0 deletions tests/deploy/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/usr/bin/env bash
set -ex
thisdir="$(dirname "$0")"
bash "$thisdir"/deploy.sh
if ls "$thisdir"/0*.sh >/dev/null; then
for test in "$thisdir"/0*.sh; do
bash -ex "$test"
done
fi
Loading