Skip to content
Merged
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
15 changes: 12 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,15 @@
"bundles windows_capability"
]
},
"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"
]
},
"windows-openssh-server": {
"description": "Optionally install Windows OpenSSH Server.",
"subdirectory": "software/windows",
Expand Down
8 changes: 5 additions & 3 deletions inventory/inventory-smartctl/policy.cf
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,12 @@ bundle agent main
);

"_sdir" string => "$(sys.statedir)";
"_cache_ttl" string => "3600";

# 1 hour
"_cache_ttl"
string => "3600",
comment => "3600 seconds 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::

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yeah, was preserving existing as much as possible.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The rest of the policy uses the linux class guard as well, often. I think probably we should not change that.

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.

yeah, it also really wants to be able to have a default context.

# Enumerate drives - extract first field from each line of smartctl --scan
"_scan_lines"
slist => splitstring(
Expand All @@ -52,7 +55,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
58 changes: 58 additions & 0 deletions software/install-ansible.cf
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# 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
#
# data:install_ansible: class, if defined, install ansible
# data:ansible_minimal_install: class, if defined, minimal install aka ansible-core
# data:ansible_full_install: class, if defined, full install. This is the default if neither minimal or full classes are defined.
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.!windows::
"Installing Ansible on a non-Linux/non-Windows host is not supported";
}

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

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 +30 to +42

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

this way seems easier to me because it leaves base_command undefined in some cases which ifelse() would not provide.

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.

Right, sometimes you want that. Sometimes I will instead use like INVALID or something so that I can explicitly know if it wasn't an expected value. Humm, could be nifty actually if there was a form of ifelse that allowed that. Like, what if you left off the last param, then it could behave exactly as this undefined policy case does but expressed in a single statement.


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

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 +48 to +51

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?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Not sure. I didn't want to implement a pipx package module so went this route instead.

}

body contain in_shell_umask(umask)
{
useshell => "true";
umask => "${umask}";
}
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
20 changes: 20 additions & 0 deletions tests/deploy/04-install-ansible-default-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 --bundle install_ansible > log
if grep 'error:' log; then
grep 'error:' log
exit 1
fi

ansible --version
echo "expect that ansible(full) is installed and not ansible-core"
if ( sudo pipx list --global --short | grep ansible-core ); then
echo "expected ansible(full) to be installed, but found ansible-core"
exit 1
fi
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