Skip to content

Commit

Permalink
Add cli class, project define and type
Browse files Browse the repository at this point in the history
  • Loading branch information
Joris29 committed Jan 16, 2024
1 parent fd21764 commit 0dd4b4b
Show file tree
Hide file tree
Showing 7 changed files with 338 additions and 0 deletions.
2 changes: 2 additions & 0 deletions data/Debian.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@ rundeck::repo_config:
key:
name: rundeck
source: https://packages.rundeck.com/pagerduty/rundeck/gpgkey

rundeck::cli::repo_config: "%{alias('rundeck::repo_config')}"
2 changes: 2 additions & 0 deletions data/RedHat.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ rundeck::repo_config:
gpgcheck: 0
enabled: 1
gpgkey: https://packages.rundeck.com/pagerduty/rundeck/gpgkey

rundeck::cli::repo_config: "%{alias('rundeck::repo_config')}"
15 changes: 15 additions & 0 deletions files/rd_project_diff.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/usr/bin/bash

project="$1"
update_method="$2"
config="$3"
keys="$4"

if [[ $update_method == 'update' ]]
then
query="jq -S 'with_entries(select(.key as \$k | \"$keys\" | index(\$k)))'"
else
query='jq -S'
fi

bash -c "diff <(rd projects configure get -p '$project' | $query) <(echo '$config' | jq -S)"
125 changes: 125 additions & 0 deletions manifests/cli.pp
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
# @summary Class to manage installation and configuration of Rundeck CLI.
#
# @example Use cli with token and project config.
# class { 'rundeck::cli':
# manage_repo => false,
# url => 'https://rundeck01.example.com',
# bypass_url => 'https://rundeck.example.com',
# token => 'very_secure',
# projects => {
# 'MyProject' => {
# 'update_method' => 'set',
# 'config' => {
# 'project.description' => 'This is My rundeck project',
# 'project.disable.executions' => 'false',
# },
# },
# 'TestProject' => {
# 'config' => {
# 'project.description' => 'This is a rundeck test project',
# 'project.disable.schedule' => 'false',
# },
# },
# },
# }
#
# @param repo_config
# A hash of repository attributes for configuring the rundeck cli package repositories.
# Examples/defaults for yumrepo can be found at RedHat.yaml, and for apt at Debian.yaml
# @param manage_repo
# Whether to manage the cli package repository.
# @param version
# Ensure the state of the rundeck cli package, either present, absent or a specific version.
# @param url
# Rundeck instance/api url.
# @param bypass_url
# Rundeck external url to bypass. This will rewrite any redirect to $bypass_url as $url
# @param user
# Cli user to authenticate.
# @param password
# Cli password to authenticate.
# @param token
# Cli token to authenticate.
# @param projects
# Cli projects config. See example for structure and rundeck::config::project for available params.
#
class rundeck::cli (
Hash $repo_config,
Boolean $manage_repo = true,
String[1] $version = 'installed',
Stdlib::HTTPUrl $url = 'http://localhost:4440',
Stdlib::HTTPUrl $bypass_url = 'http://localhost:4440',
String[1] $user = 'admin',
String[1] $password = 'admin',
Optional[String[8]] $token = undef,
Hash[String, Rundeck::Project] $projects = {},
) {
ensure_resource('package', 'jq', { 'ensure' => 'present' })

case $facts['os']['family'] {
'RedHat': {
if $manage_repo {
$repo_config.each | String $_repo_name, Hash $_attributes| {
yumrepo { $_repo_name:
* => $_attributes,
before => Package['rundeck-cli'],
}
}
}
}
'Debian': {
if $manage_repo {
$repo_config.each | String $_repo_name, Hash $_attributes| {
apt::source { $_repo_name:
* => $_attributes,
before => Package['rundeck-cli'],
}
}
}

Class['Apt::Update'] -> Package['rundeck-cli']
}
default: {
err("The osfamily: ${facts['os']['family']} is not supported")
}
}

package { 'rundeck-cli':
ensure => $version,
}

file { '/usr/local/bin/rd_project_diff.sh':
ensure => file,
content => file('rundeck/rd_project_diff.sh'),
mode => '0755',
}

$_default_env_vars = [
'RD_FORMAT=json',
"RD_URL=${url}",
"RD_BYPASS_URL=${bypass_url}",
]

if $token {
$environment = $_default_env_vars + ["RD_TOKEN=${token}"]
} else {
$environment = $_default_env_vars + ["RD_USER=${user}", "RD_PASSWORD=${password}"]
}

exec { 'Check rundeck cli connection':
command => 'rd system info',
path => ['/bin', '/usr/bin', '/usr/local/bin'],
environment => $environment,
tries => 60,
try_sleep => 5,
unless => 'rd system info &> /dev/null',
require => Package['rundeck-cli'],
}

$projects.each |$_name, $_attr| {
rundeck::config::project { $_name:
* => $_attr,
require => Exec['Check rundeck cli connection'],
}
}
}
56 changes: 56 additions & 0 deletions manifests/config/project.pp
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# @summary This define will create and manage a rundeck project.
#
# @example Basic usage.
# rundeck::config::project { 'MyProject':
# config => {
# 'project.description' => 'My test project',
# 'project.disable.schedule' => 'false',
# },
# }
#
# @param update_method
# set: Overwrite all configuration properties for a project. Any config keys not included will be removed.
# update: Modify configuration properties for a project. Only the specified keys will be updated.
# @param config
# Configuration properties for a project.
#
define rundeck::config::project (
Enum['set', 'update'] $update_method = 'update',
Hash[String, String] $config = {
'project.description' => "${title} project",
'project.disable.executions' => 'true',
'project.disable.schedule' => 'true',
},
) {
include rundeck::cli

$_default_cfg = {
'project.name' => $title,
}

$_final_cfg = $config + $_default_cfg

$_cmd_line_cfg = $_final_cfg.map |$_k, $_v| {
"--${_k}=${_v}"
}

$_project_diff = $update_method ? {
'set' => "rd_project_diff.sh '${title}' ${update_method} '${_final_cfg.to_json}'",
default => "rd_project_diff.sh '${title}' ${update_method} '${_final_cfg.to_json}' '${_final_cfg.keys}'",
}

exec {
default:
path => ['/bin', '/usr/bin', '/usr/local/bin'],
environment => $rundeck::cli::environment,
;
"Create rundeck project: ${title}":
command => "rd projects create -p ${title}",
unless => "rd projects info -p ${title}",
;
"Manage rundeck project: ${title}":
command => "rd projects configure ${update_method} -p ${title} -- ${_cmd_line_cfg.shellquote}",
unless => $_project_diff,
;
}
}
133 changes: 133 additions & 0 deletions spec/classes/cli_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
# frozen_string_literal: true

require 'spec_helper'

describe 'rundeck::cli' do
on_supported_os.each do |os, facts|
context "on #{os}" do
let :facts do
facts
end

context 'with default parameters' do
it { is_expected.to compile }

it { is_expected.to contain_package('jq').with(ensure: 'present') }

case facts[:os]['family']
when 'RedHat'
it {
is_expected.to contain_yumrepo('rundeck').with(
baseurl: 'https://packages.rundeck.com/pagerduty/rundeck/rpm_any/rpm_any/$basearch',
repo_gpgcheck: 1,
gpgcheck: 0,
enabled: 1,
gpgkey: 'https://packages.rundeck.com/pagerduty/rundeck/gpgkey'
).that_comes_before('Package[rundeck-cli]')
}
when 'Debian'
it {
is_expected.to contain_apt__source('rundeck').with(
location: 'https://packages.rundeck.com/pagerduty/rundeck/any',
release: 'any',
repos: 'main',
key: {
'name' => 'rundeck',
'source' => 'https://packages.rundeck.com/pagerduty/rundeck/gpgkey',
}
).that_comes_before('Package[rundeck-cli]')
}

it { is_expected.to contain_class('apt::update').that_comes_before('Package[rundeck-cli]') }
it { is_expected.to contain_package('rundeck-cli').with(ensure: 'installed') }
it { is_expected.to contain_file('/usr/local/bin/rd_project_diff.sh').with(ensure: 'file', mode: '0755') }

it {
is_expected.to contain_exec('Check rundeck cli connection').with(
command: 'rd system info',
path: ['/bin', '/usr/bin', '/usr/local/bin'],
environment: [
'RD_FORMAT=json',
'RD_URL=http://localhost:4440',
'RD_BYPASS_URL=http://localhost:4440',
'RD_USER=admin',
'RD_PASSWORD=admin',
],
tries: 60,
try_sleep: 5,
unless: 'rd system info &> /dev/null'
).that_requires('Package[rundeck-cli]')
}
end
end

context 'with different urls and token auth' do
let(:params) do
{
url: 'http://rundeck01.example.com',
bypass_url: 'http://rundeck.example.com',
token: 'very_secure'
}
end

it {
is_expected.to contain_exec('Check rundeck cli connection').with(
environment: [
'RD_FORMAT=json',
'RD_URL=http://rundeck01.example.com',
'RD_BYPASS_URL=http://rundeck.example.com',
'RD_TOKEN=very_secure',
]
)
}
end

context 'with projects config' do
let(:params) do
{
projects: {
'MyProject' => {
'update_method' => 'set',
'config' => {
'project.description' => 'This is My rundeck project',
'project.disable.executions' => 'false',
},
},
'TestProject' => {
'config' => {
'project.description' => 'This is a rundeck test project',
'project.disable.schedule' => 'false',
},
},
},
}
end

it {
is_expected.to contain_rundeck__config__project('MyProject').with(
update_method: 'set',
config: {
'project.description' => 'This is My rundeck project',
'project.disable.executions' => 'false',
}
)
}

it { is_expected.to contain_exec('Create rundeck project: MyProject') }
it { is_expected.to contain_exec('Manage rundeck project: MyProject') }

it {
is_expected.to contain_rundeck__config__project('TestProject').with(
config: {
'project.description' => 'This is a rundeck test project',
'project.disable.schedule' => 'false',
}
)
}

it { is_expected.to contain_exec('Create rundeck project: TestProject') }
it { is_expected.to contain_exec('Manage rundeck project: TestProject') }
end
end
end
end
5 changes: 5 additions & 0 deletions types/project.pp
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Rundeck project config type.
type Rundeck::Project = Struct[{
Optional['config'] => Hash[String, String],
Optional['update_method'] => String,
}]

0 comments on commit 0dd4b4b

Please sign in to comment.