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
42 changes: 42 additions & 0 deletions cfbs.json
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,48 @@
}
]
},
"policy-dispatcher": {
"description": "Policy dispatcher for saving policy snippets to files and running them with cf-agent",
"subdirectory": "management/policy-dispatcher",
"steps": [
"copy main.cf services/cfbs/modules/policy-dispatcher/main.cf",
"policy_files services/cfbs/modules/policy-dispatcher/main.cf",
"bundles policy_dispatcher:main",
"input ./input.json def.json"
],
"input": [
{
"type": "list",
"variable": "policy_files_to_run",
"namespace": "policy_dispatcher",
"bundle": "main",
"label": "Policy",
"subtype": [
{
"key": "policy",
"type": "string",
"label": "Policy",
"question": "Policy snippet to save and run (must contain a 'main' bundle)"
},
{
"key": "condition",
"type": "string",
"label": "Condition",
"question": "Condition for when to run",
"default": "any"
},
{
"key": "ifelapsed",
"type": "string",
"label": "ifelapsed",
"question": "Number of minutes between promise assessments",
"default": "5"
}
],
"while": "Do you want to specify more policy snippets to be run?"
}
]
},
"promise-type-ansible": {
"description": "Promise type to manage systemd services.",
"subdirectory": "promise-types/ansible",
Expand Down
4 changes: 4 additions & 0 deletions management/manage-fwupd/main.cf
Original file line number Diff line number Diff line change
Expand Up @@ -133,13 +133,15 @@ bundle agent main
"fwupd-refresh.timer"
service_policy => "enabled",
comment => "Ensure the fwupd metadata refresh timer is enabled so the LVFS firmware catalog stays current";

# --- Stale marker cleanup ----------------------------------------
files:
linux::
"$(_update_marker)"
delete => default:tidy,
if => not("_update_applied"),
comment => "Remove stale marker from a previous boot cycle";

# --- Apply firmware updates --------------------------------------
commands:
linux.default:have_fwupdmgr.manage_fwupd:apply_updates::
Expand All @@ -151,6 +153,7 @@ bundle agent main
if => and("_device_allowed_$(_dev_idx)", not("_update_applied")),
classes => default:results("bundle", "manage_fwupd_update_$(_dev_idx)"),
comment => "Apply firmware update to allowed device $(_dev_name[$(_dev_idx)])";

# --- Post-update marker and reboot --------------------------------
files:
linux.default:have_fwupdmgr.manage_fwupd:apply_updates::
Expand Down Expand Up @@ -184,6 +187,7 @@ bundle agent main
},
handle => "manage_fwupd_reboot_after_update_fallback",
comment => "Fallback reboot for non-systemd systems (shutdown -r +1)";

# --- Inventory --------------------------------------------------
vars:
linux.default:have_fwupdmgr::
Expand Down
2 changes: 2 additions & 0 deletions management/package-method-winget/package-method-winget.cf
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ body package_method winget
package_name_convention => "$(name)";
package_delete_convention => "$(name)";
package_installed_regex => ".*";

# Note that package_list_name_regex does not allow for commas inside of package names as parsing that from ConvertTo-Csv below would be too complex
# an example of output of the package_list_command below is
#
Expand All @@ -14,6 +15,7 @@ body package_method winget
# so the matches below simply grab the thing before or after the comma separating Id and InstalledVersion fields.
package_list_name_regex => '^"([^"]*)",.*';
package_list_version_regex => '.*,"([^"]*)".*';

# Here we use the Get-WinGetPackage Cmdlet because it is easier to produce easily parsed information that way
package_list_command => "$(sys.winsysdir)\\WindowsPowerShell\\v1.0\\powershell.exe -Command \"Get-WinGetPackage | Select Id,InstalledVersion | ConvertTo-Csv ";
package_delete_command => "$(sys.winsysdir)\\WindowsPowerShell\\v1.0\\powershell.exe -Command \"Uninstall-WinGetPackage ";
Expand Down
33 changes: 33 additions & 0 deletions management/policy-dispatcher/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
This module enables the running of CFEngine policy snippets based on input from Build in Mission Portal or `cfbs input`.

Each policy snippet is saved to a file in `/var/cfengine/state/policy-dispatcher/<number>.cf` and then run with `cf-agent --no-lock --file <file>`, based on the `condition`-variable.

**Note:** The policy snippets are run with root-privilege (uid=0).
Each snippet must be a complete, standalone policy file, containing a `main` bundle (this is what `cf-agent` runs by default).

**Usage:**

- `policy` - The policy snippet to save and run. Must contain a `main` bundle.
- `condition` - Condition for running. Use a class expression (e.g., `linux|bsd`). Defaults to `"any"`
- `ifelapsed` - Number of minutes between assessments. Defaults to 5 minutes.

E.g.

```json
{
"policy": "bundle agent main { reports: \"Hello World\"; } ",
"condition": "linux",
"ifelapsed": "5"
}
```

Would report "Hello World" on every linux device with 5 minute intervals.

## Contribute

Feel free to open pull requests to expand this documentation, add features or fix problems.
You can also pick up an existing task or file an issue in [our bug tracker](https://tracker.mender.io/issues/).

## License

This software is licensed under the MIT License. See LICENSE in the root of the repository for the full license text.
19 changes: 19 additions & 0 deletions management/policy-dispatcher/def.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"variables": {
"policy_dispatcher:main.policy_files_to_run": {
"value": [
{
"policy": "bundle agent main\n{\n reports:\n \"Hello World\";\n}\n",
"condition": "any",
"ifelapsed": "5"
},
{
"policy": "bundle agent main\n{\n files:\n \"/tmp/policy-dispatcher-example.txt\"\n create => \"true\",\n content => \"This file is managed by the policy-dispatcher module\n\";\n}\n",
"condition": "linux",
"ifelapsed": "60"
}
],
"comment": "Example data generated by 'cfbs input' / Mission Portal build page"
}
}
}
96 changes: 96 additions & 0 deletions management/policy-dispatcher/main.cf
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
body file control
{
namespace => "policy_dispatcher";
}

bundle agent main
{
classes:
"enabled" expression => isvariable("policy_files_to_run");

vars:
enabled::
"i" slist => getindices(policy_files_to_run);

"_policy_file[$(i)]"
string => "$(policy_files_to_run[$(i)][policy])",
if => isvariable("policy_files_to_run[$(i)][policy]");

"_condition[$(i)]"
string => ifelse(
not(strcmp("$(policy_files_to_run[$(i)][condition])", "")),
"$(policy_files_to_run[$(i)][condition])",
"any"
);

"_ifelapsed[$(i)]"
string => ifelse(
not(strcmp("$(policy_files_to_run[$(i)][ifelapsed])", "")),
"$(policy_files_to_run[$(i)][ifelapsed])",
"5"
);

"_file[$(i)]" string => "$(sys.statedir)/policy-dispatcher/$(i).cf";

"_expected_files"
slist => maplist("$(sys.statedir)/policy-dispatcher/$(this).cf", @(i));

"_actual_files"
slist => findfiles("$(sys.statedir)/policy-dispatcher/*.cf");

"_unexpected_files" slist => difference(_actual_files, _expected_files);

files:
enabled::
"$(_file[$(i)])"
create => "true",
content => "$(_policy_file[$(i)])",
perms => mo("600", "root"),
if => "$(_condition[$(i)])";

"$(_unexpected_files)" delete => tidy;

reports:
enabled.DEBUG::
"Policy file [$(i)]: $(_file[$(i)]), condition: $(_condition[$(i)]), ifelapsed: $(_ifelapsed[$(i)])";

!enabled.DEBUG::
"policy-dispatcher: policy_files_to_run variable not found";

commands:
enabled::
"$(sys.cf_agent) --no-lock --file $(_file[$(i)])"
Comment thread
olehermanse marked this conversation as resolved.
if => "$(_condition[$(i)])",
action => ifelapsed("$(_ifelapsed[$(i)])");
}

body delete tidy
# @brief Delete the file and remove empty directories
# and links to directories
{
dirlinks => "delete";
rmdirs => "true";
}

body perms mo(mode, owner)
{
mode => "$(mode)";
owners => { "$(owner)" };
rxdirs => "false";
}

body action ifelapsed(x)
{
ifelapsed => "$(x)";
}

body file control
{
namespace => "default";
}

bundle agent __main__
{
methods:
"policy_dispatcher:main";
}
Loading