diff --git a/REFERENCE.md b/REFERENCE.md index 2333c744..f29c8492 100644 --- a/REFERENCE.md +++ b/REFERENCE.md @@ -40,6 +40,7 @@ * [`Rundeck::Loglevel`](#Rundeck--Loglevel): Rundeck log level type. * [`Rundeck::Mail_config`](#Rundeck--Mail_config): Rundeck mail config type. * [`Rundeck::Project`](#Rundeck--Project): Rundeck project type. +* [`Rundeck::Scm`](#Rundeck--Scm): Rundeck scm type. ## Classes @@ -1008,6 +1009,63 @@ rundeck::config::project { 'MyProject': } ``` +##### Advanced usage with jobs. + +```puppet +rundeck::config::project { 'MyProject': + config => { + 'project.description' => 'My test project', + 'project.disable.schedule' => 'false', + }, + jobs => { + 'MyJob1' => { + 'path' => '/etc/myjob1', + 'format' => 'yaml', + }, + 'MyJob2' => { + 'path' => '/etc/myjob2', + 'format' => 'xml', + }, + 'DeleteJob1' => { + 'ensure' => 'absent', + 'path' => '/etc/testjob1', + 'format' => 'yaml', + }, + }, +} +``` + +##### Advanced usage with scm_config. + +```puppet +rundeck::config::project { 'MyProject': + config => { + 'project.description' => 'My test project', + 'project.disable.schedule' => 'false', + }, + scm_config => { + 'import' => { + 'type' => 'git-import', + 'config' => { + 'strictHostKeyChecking' => 'yes', + 'gitPasswordPath' => 'keys/example-access-token', + 'format' => 'xml', + 'dir' => '/var/lib/rundeck/projects/MyProject/ScmImport', + 'branch' => 'master', + 'url' => 'https://myuser@example.com/example/example.git', + 'filePattern' => '*.xml', + 'useFilePattern' => 'true', + 'pathTemplate' => "\${job.id}.\${config.format}", + 'importUuidBehavior' => 'preserve', + 'sshPrivateKeyPath' => '', + 'fetchAutomatically' => 'true', + 'pullAutomatically' => 'true', + }, + }, + }, +} +``` + #### Parameters The following parameters are available in the `rundeck::config::project` defined type: @@ -1016,6 +1074,10 @@ The following parameters are available in the `rundeck::config::project` defined * [`config`](#-rundeck--config--project--config) * [`update_method`](#-rundeck--config--project--update_method) * [`jobs`](#-rundeck--config--project--jobs) +* [`owner`](#-rundeck--config--project--owner) +* [`group`](#-rundeck--config--project--group) +* [`projects_dir`](#-rundeck--config--project--projects_dir) +* [`scm_config`](#-rundeck--config--project--scm_config) ##### `ensure` @@ -1065,6 +1127,38 @@ Rundeck jobs related to a project. Default value: `{}` +##### `owner` + +Data type: `String[1]` + +The user that rundeck is installed as. + +Default value: `'rundeck'` + +##### `group` + +Data type: `String[1]` + +The group permission that rundeck is installed as. + +Default value: `'rundeck'` + +##### `projects_dir` + +Data type: `Stdlib::Absolutepath` + +Directory where some project config will be stored. + +Default value: `'/var/lib/rundeck/projects'` + +##### `scm_config` + +Data type: `Optional[Rundeck::Scm]` + +A hash of name value pairs representing properties for the scm.json file. + +Default value: `undef` + ### `rundeck::config::secret` This define will manage secrets in key storage. @@ -1261,3 +1355,31 @@ Struct[{ }] ``` +### `Rundeck::Scm` + +Rundeck scm type. + +Alias of + +```puppet +Variant[Struct[{ + 'import' => Struct[{ + 'type' => String[1], + 'config' => Hash[String[1], String], + }], + Optional['export'] => Struct[{ + 'type' => String[1], + 'config' => Hash[String[1], String], + }], + }], Struct[{ + 'export' => Struct[{ + 'type' => String[1], + 'config' => Hash[String[1], String], + }], + Optional['import'] => Struct[{ + 'type' => String[1], + 'config' => Hash[String[1], String], + }], + }]] +``` + diff --git a/files/rd_scm_diff.sh b/files/rd_scm_diff.sh new file mode 100644 index 00000000..6ae8eaa6 --- /dev/null +++ b/files/rd_scm_diff.sh @@ -0,0 +1,8 @@ +#!/bin/sh +# THIS FILE IS MANAGED BY PUPPET + +projects_dir="$1" +project="$2" +interaction="$3" + +bash -c "diff <(rd projects scm config -p '$project' -i $interaction | jq .config -S) <(cat $projects_dir/$project/scm-import.json | jq .config -S)" diff --git a/manifests/cli.pp b/manifests/cli.pp index c01903e9..586242fb 100644 --- a/manifests/cli.pp +++ b/manifests/cli.pp @@ -106,6 +106,9 @@ '/usr/local/bin/rd_job_diff.sh': content => file('rundeck/rd_job_diff.sh'), ; + '/usr/local/bin/rd_scm_diff.sh': + content => file('rundeck/rd_scm_diff.sh'), + ; } $_default_env_vars = [ diff --git a/manifests/config.pp b/manifests/config.pp index af5225e6..70969930 100644 --- a/manifests/config.pp +++ b/manifests/config.pp @@ -15,6 +15,7 @@ 'framework.var.dir' => '/var/lib/rundeck/var', 'framework.tmp.dir' => '/var/lib/rundeck/var/tmp', 'framework.logs.dir' => '/var/lib/rundeck/logs', + 'framework.projects.dir' => '/var/lib/rundeck/projects', 'framework.libext.dir' => '/var/lib/rundeck/libext', 'framework.ssh.keypath' => '/var/lib/rundeck/.ssh/id_rsa', 'framework.ssh.user' => 'rundeck', diff --git a/manifests/config/project.pp b/manifests/config/project.pp index 9dba1e79..c9b55a3a 100644 --- a/manifests/config/project.pp +++ b/manifests/config/project.pp @@ -8,6 +8,57 @@ # }, # } # +# @example Advanced usage with jobs. +# rundeck::config::project { 'MyProject': +# config => { +# 'project.description' => 'My test project', +# 'project.disable.schedule' => 'false', +# }, +# jobs => { +# 'MyJob1' => { +# 'path' => '/etc/myjob1', +# 'format' => 'yaml', +# }, +# 'MyJob2' => { +# 'path' => '/etc/myjob2', +# 'format' => 'xml', +# }, +# 'DeleteJob1' => { +# 'ensure' => 'absent', +# 'path' => '/etc/testjob1', +# 'format' => 'yaml', +# }, +# }, +# } +# +# @example Advanced usage with scm_config. +# rundeck::config::project { 'MyProject': +# config => { +# 'project.description' => 'My test project', +# 'project.disable.schedule' => 'false', +# }, +# scm_config => { +# 'import' => { +# 'type' => 'git-import', +# 'config' => { +# 'strictHostKeyChecking' => 'yes', +# 'gitPasswordPath' => 'keys/example-access-token', +# 'format' => 'xml', +# 'dir' => '/var/lib/rundeck/projects/MyProject/ScmImport', +# 'branch' => 'master', +# 'url' => 'https://myuser@example.com/example/example.git', +# 'filePattern' => '*.xml', +# 'useFilePattern' => 'true', +# 'pathTemplate' => "\${job.id}.\${config.format}", +# 'importUuidBehavior' => 'preserve', +# 'sshPrivateKeyPath' => '', +# 'fetchAutomatically' => 'true', +# 'pullAutomatically' => 'true', +# }, +# }, +# }, +# } +# # @param ensure # Whether or not the project should be present. # @param config @@ -17,6 +68,14 @@ # update: Modify configuration properties for a project. Only the specified keys will be updated. # @param jobs # Rundeck jobs related to a project. +# @param owner +# The user that rundeck is installed as. +# @param group +# The group permission that rundeck is installed as. +# @param projects_dir +# Directory where some project config will be stored. +# @param scm_config +# A hash of name value pairs representing properties for the scm.json file. # define rundeck::config::project ( Enum['absent', 'present'] $ensure = 'present', @@ -34,6 +93,10 @@ }, Enum['set', 'update'] $update_method = 'update', Hash[String, Rundeck::Job] $jobs = {}, + String[1] $owner = 'rundeck', + String[1] $group = 'rundeck', + Stdlib::Absolutepath $projects_dir = '/var/lib/rundeck/projects', + Optional[Rundeck::Scm] $scm_config = undef, ) { include rundeck::cli @@ -92,5 +155,42 @@ } } } + + if $scm_config { + ensure_resource('file', "${projects_dir}/${name}", + { + 'ensure' => 'directory', + 'owner' => $owner, + 'group' => $group, + 'mode' => '0755' + } + ) + + $scm_config.each |$integration, $config| { + file { "${projects_dir}/${name}/scm-${integration}.json": + ensure => file, + owner => $owner, + group => $group, + mode => '0644', + content => stdlib::to_json($config), + } + + $_command = [ + 'rd projects scm setup', + "-p '${name}'", + "-i ${integration}", + "-t ${config['type']}", + "-f ${projects_dir}/${name}/scm-${integration}.json", + ].join(' ') + + exec { "Setup/update SCM ${integration} config for rundeck project: ${name}": + command => $_command, + path => ['/bin', '/usr/bin', '/usr/local/bin'], + environment => $rundeck::cli::environment, + unless => "rd_scm_diff.sh ${projects_dir} '${name}' ${integration}", + require => File["${projects_dir}/${name}/scm-${integration}.json"], + } + } + } } } diff --git a/spec/classes/cli_spec.rb b/spec/classes/cli_spec.rb index eb9c7af5..15ef8101 100644 --- a/spec/classes/cli_spec.rb +++ b/spec/classes/cli_spec.rb @@ -42,6 +42,7 @@ 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_file('/usr/local/bin/rd_job_diff.sh').with(ensure: 'file', mode: '0755') } + it { is_expected.to contain_file('/usr/local/bin/rd_scm_diff.sh').with(ensure: 'file', mode: '0755') } end it do diff --git a/spec/classes/config_spec.rb b/spec/classes/config_spec.rb index d0e90e02..e7483511 100644 --- a/spec/classes/config_spec.rb +++ b/spec/classes/config_spec.rb @@ -19,6 +19,7 @@ it { is_expected.to contain_file('/var/lib/rundeck/var').with(ensure: 'directory') } it { is_expected.to contain_file('/var/lib/rundeck/var/tmp').with(ensure: 'directory') } it { is_expected.to contain_file('/var/lib/rundeck/logs').with(ensure: 'directory') } + it { is_expected.to contain_file('/var/lib/rundeck/projects').with(ensure: 'directory') } it { is_expected.to contain_file('/var/log/rundeck').with(ensure: 'directory') } diff --git a/spec/defines/config/project_spec.rb b/spec/defines/config/project_spec.rb index 2ca98a6a..c0094328 100644 --- a/spec/defines/config/project_spec.rb +++ b/spec/defines/config/project_spec.rb @@ -149,6 +149,74 @@ it { is_expected.to contain_exec('(MyJobProject) Create/update job: TestJob1') } it { is_expected.to contain_exec('(MyJobProject) Remove job: DeleteJob1') } end + + context 'Add rundeck project: TestSCM with scm config' do + name = 'TestSCM' + + let(:title) { name } + let(:params) do + { + scm_config: { + 'import' => { + 'type' => 'git-import', + 'config' => { + 'strictHostKeyChecking' => 'yes', + 'gitPasswordPath' => 'keys/example-access-token', + 'format' => 'xml', + 'dir' => '/var/lib/rundeck/projects/MyProject/ScmImport', + 'branch' => 'master', + 'url' => 'https://myuser@example.com/example/example.git', + 'filePattern' => '*.xml', + 'useFilePattern' => 'true', + 'pathTemplate' => '${job.id}.${config.format}', + 'importUuidBehavior' => 'preserve', + 'sshPrivateKeyPath' => '', + 'fetchAutomatically' => 'true', + 'pullAutomatically' => 'true', + }, + }, + }, + } + end + + it { is_expected.to contain_exec('Create rundeck project: TestSCM') } + it { is_expected.to contain_exec('Manage rundeck project: TestSCM') } + it { is_expected.to contain_file('/var/lib/rundeck/projects/TestSCM').with(ensure: 'directory', owner: 'rundeck', group: 'rundeck', mode: '0755') } + it { is_expected.to contain_file('/var/lib/rundeck/projects/TestSCM/scm-import.json').with(ensure: 'file', owner: 'rundeck', group: 'rundeck', mode: '0644') } + it { is_expected.to contain_exec('Setup/update SCM import config for rundeck project: TestSCM').that_requires('File[/var/lib/rundeck/projects/TestSCM/scm-import.json]') } + end + + context 'Add rundeck project: TestWrongSCM with wrong scm config' do + name = 'TestWrongSCM' + + let(:title) { name } + let(:params) do + { + scm_config: { + 'wrong_key' => { + 'type' => 'git-import', + 'config' => { + 'strictHostKeyChecking' => 'yes', + 'gitPasswordPath' => 'keys/example-access-token', + 'format' => 'xml', + 'dir' => '/var/lib/rundeck/projects/MyProject/ScmImport', + 'branch' => 'master', + 'url' => 'https://myuser@example.com/example/example.git', + 'filePattern' => '*.xml', + 'useFilePattern' => 'true', + 'pathTemplate' => '${job.id}.${config.format}', + 'importUuidBehavior' => 'preserve', + 'sshPrivateKeyPath' => '', + 'fetchAutomatically' => 'true', + 'pullAutomatically' => 'true', + }, + }, + }, + } + end + + it { is_expected.not_to compile } + end end end end diff --git a/types/scm.pp b/types/scm.pp new file mode 100644 index 00000000..5b2268be --- /dev/null +++ b/types/scm.pp @@ -0,0 +1,23 @@ +# @summary Rundeck scm type. +type Rundeck::Scm = Variant[ + Struct[{ + 'import' => Struct[{ + 'type' => String[1], + 'config' => Hash[String[1], String], + }], + Optional['export'] => Struct[{ + 'type' => String[1], + 'config' => Hash[String[1], String], + }], + }], + Struct[{ + 'export' => Struct[{ + 'type' => String[1], + 'config' => Hash[String[1], String], + }], + Optional['import'] => Struct[{ + 'type' => String[1], + 'config' => Hash[String[1], String], + }], + }], +]