kafo 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of kafo might be problematic. Click here for more details.
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +11 -0
- data/README.md +269 -0
- data/Rakefile +1 -0
- data/bin/kafo-configure +8 -0
- data/bin/kafofy +36 -0
- data/config/config_header.txt +8 -0
- data/config/kafo.yaml.example +11 -0
- data/kafo.gemspec +36 -0
- data/lib/kafo.rb +2 -0
- data/lib/kafo/configuration.rb +87 -0
- data/lib/kafo/exceptions.rb +5 -0
- data/lib/kafo/kafo_configure.rb +180 -0
- data/lib/kafo/logger.rb +41 -0
- data/lib/kafo/param.rb +65 -0
- data/lib/kafo/param_builder.rb +59 -0
- data/lib/kafo/params/array.rb +18 -0
- data/lib/kafo/params/boolean.rb +21 -0
- data/lib/kafo/params/integer.rb +14 -0
- data/lib/kafo/params/string.rb +3 -0
- data/lib/kafo/puppet_module.rb +93 -0
- data/lib/kafo/puppet_module_parser.rb +65 -0
- data/lib/kafo/string_helper.rb +19 -0
- data/lib/kafo/system_checker.rb +31 -0
- data/lib/kafo/validator.rb +59 -0
- data/lib/kafo/version.rb +3 -0
- data/lib/kafo/wizard.rb +131 -0
- data/modules/kafo_configure/lib/puppet/parser/functions/class_name.rb +18 -0
- data/modules/kafo_configure/lib/puppet/parser/functions/dump_values.rb +9 -0
- data/modules/kafo_configure/lib/puppet/parser/functions/hash_keys.rb +15 -0
- data/modules/kafo_configure/lib/puppet/parser/functions/is_hash.rb +22 -0
- data/modules/kafo_configure/lib/puppet/parser/functions/loadanyyaml.rb +37 -0
- data/modules/kafo_configure/manifests/init.pp +17 -0
- data/modules/kafo_configure/manifests/yaml_to_class.pp +24 -0
- metadata +197 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
This program and entire repository is free software: you can redistribute it
|
2
|
+
and/or modify it under the terms of the GNU General Public License as
|
3
|
+
published by the Free Software Foundation, either version 3 of the License,
|
4
|
+
or any later version.
|
5
|
+
|
6
|
+
This program is distributed in the hope that it will be useful, but WITHOUT
|
7
|
+
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
8
|
+
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
9
|
+
|
10
|
+
You should have received a copy of the GNU General Public License along with
|
11
|
+
this program. If not, see http://www.gnu.org/licenses/.
|
data/README.md
ADDED
@@ -0,0 +1,269 @@
|
|
1
|
+
# Kafo
|
2
|
+
|
3
|
+
A puppet based installer and configurer (not-only) for Foreman and Katello
|
4
|
+
projects. Kafo is a ruby gem that allows you to create fancy user interfaces for
|
5
|
+
puppet modules. It's some kind of a nice frontend to a
|
6
|
+
|
7
|
+
```bash
|
8
|
+
echo "include some_modules" | puppet apply
|
9
|
+
```
|
10
|
+
## Why should I care?
|
11
|
+
|
12
|
+
Suppose you work on a software which you want to distribute to a machine in
|
13
|
+
infrastructure managed by puppet. You write a puppet module for your app.
|
14
|
+
But you also want to be able to distribute this app to a machine outside of
|
15
|
+
puppet infrastructure (e.g. install it to your clients) or you want to install
|
16
|
+
it in order to create a puppet infrastructure itself (e.g. foreman or
|
17
|
+
foreman-proxy).
|
18
|
+
|
19
|
+
With kafo you can reuse your puppet modules for creating an installer. Even
|
20
|
+
better after the installation you can easily modify you configuration. All
|
21
|
+
using the very same puppet modules.
|
22
|
+
|
23
|
+
## What it does, how does it work?
|
24
|
+
|
25
|
+
Kafo reads a config file to find out which modules should it use. Then it
|
26
|
+
loads parameters from puppet manifests and gives you a way to customize them.
|
27
|
+
|
28
|
+
There are three ways how you can set parameters. You can
|
29
|
+
* predefine them in configuration file
|
30
|
+
* specify them as CLI arguments
|
31
|
+
* you can use interactive mode which will ask you for all required parameters
|
32
|
+
|
33
|
+
Note that your answers (gathered from any mode) are saved for the next run
|
34
|
+
so you don't have to specify them again. Kafo also support default values of
|
35
|
+
parameters so you can set only those you want to change. Also you can combine
|
36
|
+
akk modes so you can create an answer file with default values easily
|
37
|
+
and then use it for unattended installs.
|
38
|
+
|
39
|
+
## How do I use it?
|
40
|
+
|
41
|
+
First install kafo gem.
|
42
|
+
|
43
|
+
Using bundler - add kafo gem to your Gemfile and run
|
44
|
+
```bash
|
45
|
+
bundle install
|
46
|
+
```
|
47
|
+
|
48
|
+
or without bundler
|
49
|
+
```bash
|
50
|
+
gem install kafo
|
51
|
+
```
|
52
|
+
|
53
|
+
Create a directory for your installer. Let's say we want to create
|
54
|
+
foreman-installer.
|
55
|
+
|
56
|
+
```bash
|
57
|
+
mkdir foreman-installer
|
58
|
+
cd foreman-installer
|
59
|
+
```
|
60
|
+
|
61
|
+
Now we run +kafofy+ script which will prepare directory structure and
|
62
|
+
optionally create a bin script according to first parameter.
|
63
|
+
|
64
|
+
```bash
|
65
|
+
kafofy foreman-installer
|
66
|
+
```
|
67
|
+
|
68
|
+
You can see that it created modules directory where your puppet modules
|
69
|
+
should live. It also created config and bin directories. If you specified
|
70
|
+
argument (foreman-installer in this case) a script in bin was created.
|
71
|
+
It's the script you can use to run installer. If you did not specify any
|
72
|
+
you can run your installer by +kafo-configure+ which is provided by the gem.
|
73
|
+
All configuration related files are to be found in config directory.
|
74
|
+
|
75
|
+
So for example to install foreman you want to
|
76
|
+
```bash
|
77
|
+
cd foreman-installer/modules
|
78
|
+
git clone https://github.com/theforeman/puppet-foreman/ foreman
|
79
|
+
```
|
80
|
+
Currently you must also download any dependant modules.
|
81
|
+
Then you need to tell kafo it's going to use foreman module.
|
82
|
+
```bash
|
83
|
+
cd ..
|
84
|
+
echo "foreman: true" > config/answers.yaml
|
85
|
+
```
|
86
|
+
Fire it with -h
|
87
|
+
```bash
|
88
|
+
bin/foreman-installer -h
|
89
|
+
```
|
90
|
+
|
91
|
+
You will see all arguments that you can pass to kafo. Note that underscored
|
92
|
+
puppet parameters are automatically converted to dashed arguments. You can
|
93
|
+
also see a documentation extracted from foreman puppet module and default
|
94
|
+
value.
|
95
|
+
|
96
|
+
Now run it without -h argument. It will print you the puppet apply command
|
97
|
+
to execute. This will be automatized later. Look at config/answers.yaml, it
|
98
|
+
was populated with default values. To change those options you can use
|
99
|
+
arguments like this
|
100
|
+
|
101
|
+
```bash
|
102
|
+
bin/foreman-installer --foreman-enc=false --foreman-db-type=sqlite
|
103
|
+
```
|
104
|
+
|
105
|
+
or you can run interactive mode
|
106
|
+
|
107
|
+
```bash
|
108
|
+
bin/foreman-installer --interactive
|
109
|
+
```
|
110
|
+
|
111
|
+
Also every change made to config/answers.yaml persists and becomes new default
|
112
|
+
value for next run.
|
113
|
+
|
114
|
+
As you noticed there are several ways how to specify arguments. Here's the list
|
115
|
+
the lower the item is the higher precedence it has:
|
116
|
+
* default values from puppet modules
|
117
|
+
* values from answers.yaml
|
118
|
+
* values specified on CLI
|
119
|
+
* interactive mode arguments
|
120
|
+
|
121
|
+
# Advanced topics
|
122
|
+
|
123
|
+
## Testing aka noop
|
124
|
+
|
125
|
+
You'll probably want to tweak your installer before so you may find --noop
|
126
|
+
argument handy. This will run puppet in noop so no change will be done to your
|
127
|
+
system. Default value is false!
|
128
|
+
|
129
|
+
## Documentation
|
130
|
+
|
131
|
+
Every parameter that can be set by kafo *must* be documented. This means that
|
132
|
+
you must add documentation to your puppet class in init.pp. It's basically
|
133
|
+
rdoc formatted documentation that must be above class definitions. There can
|
134
|
+
be no space between doc block and class definition.
|
135
|
+
|
136
|
+
Example:
|
137
|
+
```puppet
|
138
|
+
# Manage your foreman server
|
139
|
+
#
|
140
|
+
# This class ...
|
141
|
+
# ... does what it does.
|
142
|
+
#
|
143
|
+
# === Parameters:
|
144
|
+
#
|
145
|
+
# $foreman_url:: URL on which foreman is going to run
|
146
|
+
#
|
147
|
+
# $enc:: Should foreman act as an external node classifier (manage puppet class
|
148
|
+
# assignments)
|
149
|
+
# type:boolean
|
150
|
+
class foreman (
|
151
|
+
$foreman_url = $foreman::params::foreman_url,
|
152
|
+
$enc = $foreman::params::enc
|
153
|
+
) {
|
154
|
+
class { 'foreman::install': }
|
155
|
+
}
|
156
|
+
```
|
157
|
+
|
158
|
+
## Argument types
|
159
|
+
|
160
|
+
By default all arguments that are parsed from puppet are treated as string.
|
161
|
+
If you want to indicate that a parameter has a particular type you can do it
|
162
|
+
in puppet manifest documentation like this
|
163
|
+
|
164
|
+
```puppet
|
165
|
+
# $param:: Some documentation for param
|
166
|
+
type:boolean
|
167
|
+
```
|
168
|
+
|
169
|
+
Supported types are: string, boolean, integer, array
|
170
|
+
|
171
|
+
Note that all arguments that are nil (have no value in answers.yaml or you
|
172
|
+
set them UNDEF (see below) are translated to ```undef``` in puppet.
|
173
|
+
|
174
|
+
## Array arguments
|
175
|
+
|
176
|
+
Some arguments may be Arrays. If you want to specify array values you can
|
177
|
+
specify CLI argument multiple times e.g.
|
178
|
+
```bash
|
179
|
+
bin/foreman-installer --puppetmaster-environments=development --puppetmaster-environments=production
|
180
|
+
```
|
181
|
+
|
182
|
+
In interactive mode you'll be prompted for another value until you specify
|
183
|
+
blank line.
|
184
|
+
|
185
|
+
## Validations
|
186
|
+
|
187
|
+
If you specify validations of parameters in you init.pp manifest they
|
188
|
+
will be executed for your values even before puppet is run. In order to do this
|
189
|
+
you must follow few rules however:
|
190
|
+
|
191
|
+
* you must use standard validation functions (e.g. validate_array, validate_re, ...)
|
192
|
+
* you must have stdlib in modules directory
|
193
|
+
|
194
|
+
## Enabling or disabling module
|
195
|
+
|
196
|
+
You can enable or disable module specified in answers.yaml file. Every module
|
197
|
+
automatically adds two options to foreman-installer script. For module foreman
|
198
|
+
you have two flag options ```--enable-foreman``` and ```--no-enable-foreman```.
|
199
|
+
|
200
|
+
When you disable a module all its answers will be removed and module will be
|
201
|
+
set to false. When you reenable the module you'll end up with default values.
|
202
|
+
|
203
|
+
## Special values for arguments
|
204
|
+
|
205
|
+
Sometimes you may want to enforce ```undef``` value for a particular parameter.
|
206
|
+
You can set this value by specifying UNDEF string e.g.
|
207
|
+
|
208
|
+
```bash
|
209
|
+
bin/foreman-installer --foreman-db-password=UNDEF
|
210
|
+
```
|
211
|
+
|
212
|
+
It also works in interactive mode.
|
213
|
+
|
214
|
+
## Changing of log directory and user/group
|
215
|
+
|
216
|
+
By default kafo logs every run to a separate file in /var/log/kafo.
|
217
|
+
You probably want to put your installation logs alongside with other logs of
|
218
|
+
your application. That's why kafo has its own configuration file in which you
|
219
|
+
can tune details like this.
|
220
|
+
|
221
|
+
In order to do that create a configuration file in config/kafo.yaml. You can
|
222
|
+
use config/kafo.yaml.example as a template. If config/kafo.yaml does not exist
|
223
|
+
default values will be used.
|
224
|
+
|
225
|
+
As a developer you can appreciate more verbose log. You can set debug level
|
226
|
+
in config/kafo.yml. Also you can change a user or group that will own the
|
227
|
+
log file. This is usefull if your installer requires to be run under root
|
228
|
+
but you want the logs to be readable by specific users.
|
229
|
+
|
230
|
+
## System checks
|
231
|
+
|
232
|
+
When you want to make sure that user has some software installed or has the
|
233
|
+
right version you can write a simple script and put it into checks directory.
|
234
|
+
All files found there will be ran and if any has non-zero exit code, kafo
|
235
|
+
wont execute puppet.
|
236
|
+
|
237
|
+
Everything on STDOUT is logged in debug level, everything on STDERR is logged
|
238
|
+
in error level.
|
239
|
+
|
240
|
+
Example shell script which checks java version
|
241
|
+
|
242
|
+
```bash
|
243
|
+
#!/bin/sh
|
244
|
+
java -version 2>&1 | grep OpenJDK
|
245
|
+
exit $?
|
246
|
+
```
|
247
|
+
|
248
|
+
## Exit code
|
249
|
+
|
250
|
+
Kafo can terminate either before or after puppet is ran. Puppet is ran with
|
251
|
+
--detailed-exitcodes and Kafo returns the same exit code as puppet does. If
|
252
|
+
kafo terminates after puppet run exit codes are:
|
253
|
+
* '2' means there were changes,
|
254
|
+
* '4' means there were failures during the transaction,
|
255
|
+
* '6' means there were both changes and failures.
|
256
|
+
|
257
|
+
Other exit codes that can be returned:
|
258
|
+
* '0' means everything went fine no changes were made
|
259
|
+
* '20' means your system does not meet configuration criteria (system checks failed)
|
260
|
+
* '21' means your answer file contains invalid values
|
261
|
+
* '22' means that puppet modules contains some error (e.g. missing documentation)
|
262
|
+
* '23' means that you have no answer file
|
263
|
+
* '24' means that your answer file asks for puppet module that you did not provide
|
264
|
+
* '25' means that kafo could not get default values from puppet
|
265
|
+
|
266
|
+
|
267
|
+
# License
|
268
|
+
|
269
|
+
This project is licensed under the GPLv3+.
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/kafo-configure
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# TODO cover with tests
|
4
|
+
# TODO validations: "puppet master --compile <fqdn>" compiles a catalog for a given host but it uses the global manifest/modules rather than stdin.. but by specifying --manifestdir you could get it to read a site.pp that contains the "include kafo_configure"
|
5
|
+
|
6
|
+
$LOAD_PATH.unshift File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'kafo'))
|
7
|
+
require 'kafo_configure'
|
8
|
+
KafoConfigure.run
|
data/bin/kafofy
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
# Create directory structure
|
6
|
+
%w(bin config modules).each do |dir|
|
7
|
+
FileUtils.mkdir_p dir
|
8
|
+
end
|
9
|
+
|
10
|
+
# Copy config files
|
11
|
+
src = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
12
|
+
%w(config_header.txt kafo.yaml.example).each do |file|
|
13
|
+
FileUtils.cp src + "/config/#{file}", 'config/'
|
14
|
+
end
|
15
|
+
|
16
|
+
script_name = "kafo-configure"
|
17
|
+
# Optional configure script
|
18
|
+
if ARGV.size > 0
|
19
|
+
name = ARGV[0]
|
20
|
+
script_name = "bin/#{name}"
|
21
|
+
puts "... creating #{script_name}"
|
22
|
+
content = <<EOS
|
23
|
+
#!/usr/bin/env ruby
|
24
|
+
require 'kafo'
|
25
|
+
KafoConfigure.run
|
26
|
+
EOS
|
27
|
+
File.write script_name, content
|
28
|
+
FileUtils.chmod 0755, script_name
|
29
|
+
end
|
30
|
+
|
31
|
+
puts "Your directory was kafofied"
|
32
|
+
|
33
|
+
puts "Now you should:"
|
34
|
+
puts " 1. upload your puppet modules to modules directory"
|
35
|
+
puts " 2. create default config/answers.yaml"
|
36
|
+
puts " 3. run #{script_name}"
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# kafo main configuration file example
|
2
|
+
# you can rename it to kafo.yaml so it overwrite default kafo settings
|
3
|
+
# useful for development, e.g. when you want to move log files to local directory
|
4
|
+
|
5
|
+
# :log_dir: '/var/log/kafo'
|
6
|
+
# :log_level: :info
|
7
|
+
|
8
|
+
# Advanced configuration - if not set it's ignored
|
9
|
+
# :log_owner: root
|
10
|
+
# :log_group: root
|
11
|
+
|
data/kafo.gemspec
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
$LOAD_PATH.unshift(lib + '/kafo')
|
5
|
+
$LOAD_PATH.unshift(lib + '/kafo/params')
|
6
|
+
require 'kafo/version'
|
7
|
+
|
8
|
+
Gem::Specification.new do |spec|
|
9
|
+
spec.name = "kafo"
|
10
|
+
spec.version = Kafo::VERSION
|
11
|
+
spec.authors = ["Marek Hulan"]
|
12
|
+
spec.email = ["ares@igloonet.cz"]
|
13
|
+
spec.description = %q{A gem for making installations based on puppet user friendly}
|
14
|
+
spec.summary = %q{If you write puppet modules for installing your software, you can use kafo to create powerful installer}
|
15
|
+
spec.homepage = "https://github.com/theforeman/kafo-configure"
|
16
|
+
spec.license = "GPLv3+"
|
17
|
+
|
18
|
+
spec.files = `git ls-files`.split($/)
|
19
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
20
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
21
|
+
spec.require_paths = ["lib"]
|
22
|
+
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
24
|
+
spec.add_development_dependency "rake"
|
25
|
+
|
26
|
+
# puppet manifests parsing
|
27
|
+
spec.add_dependency 'puppet'
|
28
|
+
spec.add_dependency 'rdoc', '~> 3.0'
|
29
|
+
# better logging
|
30
|
+
spec.add_dependency 'logging'
|
31
|
+
# CLI interface
|
32
|
+
spec.add_dependency 'clamp'
|
33
|
+
# interactive mode
|
34
|
+
spec.add_dependency 'highline'
|
35
|
+
|
36
|
+
end
|
data/lib/kafo.rb
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'kafo/puppet_module'
|
3
|
+
|
4
|
+
class Configuration
|
5
|
+
attr_reader :config_file
|
6
|
+
|
7
|
+
|
8
|
+
begin
|
9
|
+
default_hash = YAML.load_file(File.join(Dir.pwd, 'config/kafo.yaml'))
|
10
|
+
rescue => e
|
11
|
+
default_hash = {}
|
12
|
+
end
|
13
|
+
KAFO = {
|
14
|
+
:log_dir => '/var/log/kafo',
|
15
|
+
:log_level => :info,
|
16
|
+
}.merge(default_hash || {})
|
17
|
+
|
18
|
+
def initialize(file)
|
19
|
+
@logger = Logging.logger.root
|
20
|
+
@logger.info "Loading config file #{file}"
|
21
|
+
|
22
|
+
begin
|
23
|
+
@data = YAML.load_file file
|
24
|
+
rescue Errno::ENOENT => e
|
25
|
+
puts "No answers file at #{file} found, can not continue"
|
26
|
+
exit(23)
|
27
|
+
end
|
28
|
+
|
29
|
+
@config_file = file
|
30
|
+
@config_dir = File.join(Dir.pwd, 'config')
|
31
|
+
end
|
32
|
+
|
33
|
+
def modules
|
34
|
+
@modules ||= @data.keys.map { |mod| PuppetModule.new(mod).parse }
|
35
|
+
end
|
36
|
+
|
37
|
+
def params_default_values
|
38
|
+
@params_default_values ||= begin
|
39
|
+
@logger.info "Parsing default values from puppet modules..."
|
40
|
+
# TODO not dry, kafo_configure.rb does similar thing
|
41
|
+
modules_path = "modules:#{File.join(gem_root_path, '../../modules')}"
|
42
|
+
@logger.debug `echo '#{includes} dump_values(#{params})' | puppet apply --modulepath #{modules_path} 2>&1`
|
43
|
+
unless $?.exitstatus == 0
|
44
|
+
@logger.error "Could not get default values, cannot continue"
|
45
|
+
exit(25)
|
46
|
+
end
|
47
|
+
@logger.info "... finished"
|
48
|
+
YAML.load_file(File.join(@config_dir, 'default_values.yaml'))
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# if a value is a true we return empty hash because we have no specific options for a
|
53
|
+
# particular puppet module
|
54
|
+
def [](key)
|
55
|
+
value = @data[key]
|
56
|
+
value.is_a?(Hash) ? value : {}
|
57
|
+
end
|
58
|
+
|
59
|
+
def module_enabled?(mod)
|
60
|
+
value = @data[mod.name]
|
61
|
+
!!value || value.is_a?(Hash)
|
62
|
+
end
|
63
|
+
|
64
|
+
def config_header
|
65
|
+
@config_header ||= File.read(File.join(gem_root_path, '/config/config_header.txt'))
|
66
|
+
end
|
67
|
+
|
68
|
+
def gem_root_path
|
69
|
+
@gem_root_path ||= File.join(File.dirname(__FILE__), '../../')
|
70
|
+
end
|
71
|
+
|
72
|
+
def store(data)
|
73
|
+
File.write(config_file, config_header + YAML.dump(data))
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
def includes
|
79
|
+
modules.map { |mod| "include #{mod.dir_name}::params" }.join(' ')
|
80
|
+
end
|
81
|
+
|
82
|
+
def params
|
83
|
+
params = modules.map(&:params).flatten
|
84
|
+
params = params.select { |p| p.default != 'UNSET' }
|
85
|
+
params.map { |param| "#{param.default}" }.join(',')
|
86
|
+
end
|
87
|
+
end
|