puppet-validator 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 27540dfa278a0cc463d85b7ed95420957b9f061f
4
+ data.tar.gz: 5d0c51971ca899cbddef2b63164722f18a0c8d68
5
+ SHA512:
6
+ metadata.gz: dfc4006d55991a8d84d381ef4be02a95e5df9e12164699509ed70e79b07cd68ccfbc5fa8059495748977d0ee5809c701ee435f6358a27f85f2744b04ec9a83f0
7
+ data.tar.gz: 753d447bf1e0cbcfc967da5fad07eecd85b2f3004eb37e58b230d8a0fa9fefca6c23f127532a85d22193eb38a0ef8f789aa5e34501af6cfab74534c7a3fce459
data/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright (c) 2015 Puppet Labs, eduteam@puppetlabs.com
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,149 @@
1
+ # Puppet Validator:
2
+ ## Puppet Code Validation as a service
3
+
4
+ Puppet Validator is a simple web service that accepts arbitrary code submissions and
5
+ validates it the way `puppet parser validate` would. It can optionally also
6
+ run `puppet-lint` checks on the code and display both results together.
7
+
8
+ Puppet Validator is completely themeable, albeit rather primitively.
9
+
10
+ ### Usage:
11
+
12
+ #### Running the service directly
13
+
14
+ puppet-validator [-p <port>] [-l [logfile]] [-t <themedir>] [-d]
15
+ ↳ Runs the Puppet Validator code validation service.
16
+
17
+ This is the simplest way to run Puppet Validator. It has no external dependencies, other
18
+ than the handful of gems it uses. This command will start the service. It will
19
+ not daemonize itself, though a `systemd` init script is provided that will take
20
+ care of that for you. It will default to running on port 9000, and will serve
21
+ content directly out of its installation directory. You can override and customize
22
+ the web content by passing the `-t` or `--theme` command-line argument. See
23
+ [Creating your own theme](#creating-your-own-theme) below.
24
+
25
+ Options:
26
+
27
+ -d, --debug Display or log debugging messages
28
+ -l, --logfile [LOGFILE] Path to logfile. Defaults to no logging, or
29
+ /var/log/puppet-validator if no filename is passed.
30
+ -p, --port PORT Port to listen on. Defaults to 9000.
31
+ -t, --theme THEMEDIR Path to the theme directory.
32
+
33
+ -h, --help Displays this help
34
+
35
+ #### Integrating with Middleware
36
+
37
+ If you plan to run this as a public service, then you may want to run it under
38
+ middleware, such as Phusion Passenger, for performance and scalability. The
39
+ specific implementation will depend on your choice of webserver and middleware.
40
+
41
+ To configure Puppet Validator on Apache and Passenger, you'll need to
42
+ <a href="https://www.phusionpassenger.com/library/install/apache/install/oss/el7/">
43
+ install and configure the appropriate packages</a>. Then you'll need to configure
44
+ a virtual host to contain the application.
45
+
46
+ ``` Apache
47
+ # /etc/httpd/conf.d/puppet-validator.conf
48
+ Listen 9090
49
+ <VirtualHost *:9090>
50
+ ServerName 54.201.129.11
51
+ DocumentRoot /etc/puppet-validator/public
52
+ <Directory /etc/puppet-validator/public>
53
+ Require all granted
54
+ Allow from all
55
+ Options -MultiViews
56
+ </Directory>
57
+ </VirtualHost>
58
+ ```
59
+
60
+ The `DocumentRoot` and `Directory` directives can point directly to the `public`
61
+ directory *within the gem installation directory*, or it can point to the `public`
62
+ directory of a custom theme you've created. See
63
+ [Creating your own theme](#creating-your-own-theme) below. The two directives
64
+ should point to the same directory.
65
+
66
+ In the directory directly above the `public` directory referenced above, you
67
+ should have a `config.ru` file. This file will actually bootstrap and start the
68
+ application. An example file exists in the root of the gem installation directory.
69
+ It looks similar to the file below and may be customized to pass in any options
70
+ you'd like.
71
+
72
+ ``` Ruby
73
+ # /etc/puppet-validator/config.ru
74
+ require 'rubygems'
75
+ require 'puppet-validator'
76
+
77
+ logger = Logger.new('/var/log/puppet-validator')
78
+ logger.level = Logger::WARN
79
+
80
+ PuppetValidator.set :root, File.dirname(__FILE__)
81
+ PuppetValidator.set :logger, logger
82
+
83
+ run PuppetValidator
84
+ ```
85
+
86
+ #### Creating your own theme
87
+
88
+ Creating a Puppet Validator theme is as simple as copying the content files to a directory
89
+ and customizing them. The `init` subcommand will do this for you. Note that the
90
+ command *will overwrite* existing files, but it will warn you before it does so.
91
+
92
+ root@master:~ # mkdir /etc/puppet-validator
93
+ root@master:~ # cd /etc/puppet-validator/
94
+ root@master:/etc/puppet-validator # puppet-validator init
95
+ Initializing directory as new Puppet Validator theme...
96
+ root@master:/etc/puppet-validator # tree
97
+ .
98
+ ├── LICENSE
99
+ ├── README.md
100
+ ├── config.ru
101
+ ├── public
102
+ │   ├── info.png
103
+ │   ├── prism-default.css
104
+ │   ├── prism.js
105
+ │   ├── styles.css
106
+ │   └── testing.html
107
+ └── views
108
+ ├── index.erb
109
+ └── result.erb
110
+
111
+ Once you've created your theme, you can start the Puppet Validator service using the `-t`
112
+ or `--theme` command line arguments to tell Puppet Validator where to find your content.
113
+
114
+ root@master:~ # puppet-validator -t /etc/puppet-validator/
115
+
116
+ Alternatively, you can edit your webserver virtual host configuration to point
117
+ to the *public* directory within your new theme, as in the example shown above.
118
+
119
+ #### Disabling `puppet-lint` checks
120
+
121
+ Puppet-lint is an incredibly valuable tool. That said, some of the checks it runs
122
+ may not apply to your environment. It's easy to disable these checks, either on
123
+ the command-line, or in the `config.ru` file. By default, Puppet Validator will just run
124
+ all available checks.
125
+
126
+ Checks can be disabled either as a comma-separated list of checks:
127
+
128
+ root@master:~ # puppet-validator --disable 80chars,double_quoted_strings
129
+
130
+ Or in a file with one check per line.
131
+
132
+ root@master:~ # puppet-validator --disable /etc/puppet-validator/disabled_checks
133
+ root@master:~ # cat /etc/puppet-validator/disabled_checks
134
+ 80chars
135
+ double_quoted_strings
136
+
137
+ This can also be done in your `config.ru`. Specifying a list would look like this:
138
+
139
+ ``` Ruby
140
+ PuppetValidator.set :disabled_lint_checks, ['80chars', 'double_quoted_strings']
141
+
142
+ ```
143
+
144
+ And loading the disabled checks from a file would look like:
145
+
146
+ ``` Ruby
147
+ PuppetValidator.set :disabled_lint_checks, '/etc/puppet-validator/disabled_checks'
148
+
149
+ ```
@@ -0,0 +1,78 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'optparse'
5
+ require 'puppet-validator'
6
+
7
+ gemroot = File.expand_path(File.join(File.dirname(__FILE__), '..'))
8
+ options = {
9
+ :port => 9000,
10
+ :host => '0.0.0.0',
11
+ :bind => '0.0.0.0',
12
+ :root => gemroot,
13
+ }
14
+ logfile = $stderr
15
+ loglevel = Logger::WARN
16
+
17
+ optparse = OptionParser.new { |opts|
18
+ opts.banner = "Usage : puppet-validator [-p <port>] [-l [logfile]] [-t <themedir>] [-d]
19
+ ↳ Runs the Puppet Validator code validation service.
20
+
21
+ puppet-validator init
22
+ ↳ Copies the files needed to create a puppet-validator theme into $CWD.
23
+ This will overwrite existing files.
24
+
25
+ "
26
+
27
+ opts.on("-d", "--debug", "Display or log debugging messages") do
28
+ loglevel = Logger::DEBUG
29
+ end
30
+
31
+ opts.on("--disable DISABLED_CHECKS", "Lint checks to disable. Either comma-separated list or filename.") do |arg|
32
+ puts "Disabling #{arg}"
33
+ options[:disabled_lint_checks] = arg
34
+ end
35
+
36
+ opts.on("-l [LOGFILE]", "--logfile [LOGFILE]", "Path to logfile. Defaults to no logging, or /var/log/puppet-validator if no filename is passed.") do |arg|
37
+ logfile = arg || '/var/log/puppet-validator'
38
+ end
39
+
40
+ opts.on("-p PORT", "--port", "Port to listen on. Defaults to 9000.") do |arg|
41
+ options[:port] = arg
42
+ end
43
+
44
+ opts.on("-t THEMEDIR", "--theme THEMEDIR", "Path to the theme directory.") do |arg|
45
+ options[:root] = arg
46
+ end
47
+
48
+ opts.separator('')
49
+
50
+ opts.on("-h", "--help", "Displays this help") do
51
+ puts
52
+ puts opts
53
+ puts
54
+ exit
55
+ end
56
+ }
57
+ optparse.parse!
58
+
59
+ if ARGV.first == 'init'
60
+ puts 'Initializing directory as new puppet-validator theme...'
61
+ unless (Dir.glob '**/*').empty?
62
+ puts '-- Overwriting existing files. Press Ctrl-C to cancel or <Enter> to continue.'
63
+ STDIN.gets
64
+ end
65
+
66
+ FileUtils.cp "#{gemroot}/config.ru", '.'
67
+ FileUtils.cp "#{gemroot}/LICENSE", '.'
68
+ FileUtils.cp "#{gemroot}/README.md", '.'
69
+ FileUtils.cp_r "#{gemroot}/public", '.'
70
+ FileUtils.cp_r "#{gemroot}/views", '.'
71
+
72
+ else
73
+ logger = Logger.new(logfile)
74
+ logger.level = loglevel
75
+ options[:logger] = logger
76
+
77
+ PuppetValidator.run! options
78
+ end
data/config.ru ADDED
@@ -0,0 +1,11 @@
1
+ require 'rubygems'
2
+ require 'puppet-validator'
3
+
4
+ logger = Logger.new('/var/log/puppet-validator')
5
+ logger.level = Logger::WARN
6
+
7
+ PuppetValidator.set :root, File.dirname(__FILE__)
8
+ PuppetValidator.set :logger, logger
9
+ PuppetValidator.set :disabled_lint_checks, ['80chars']
10
+
11
+ run PuppetValidator
@@ -0,0 +1,132 @@
1
+ require 'logger'
2
+ require 'sinatra/base'
3
+ require 'puppet'
4
+ require 'puppet/parser'
5
+ require 'puppet-lint'
6
+
7
+ # something like 3,000 lines of code
8
+ MAXSIZE = 100000
9
+ CONTEXT = 3
10
+
11
+ class PuppetValidator < Sinatra::Base
12
+ set :logging, true
13
+ set :strict, true
14
+
15
+ before {
16
+ env["rack.logger"] = settings.logger if settings.logger
17
+ }
18
+
19
+ def initialize(app=nil)
20
+ super(app)
21
+
22
+ # there must be a better way
23
+ if settings.respond_to? :disabled_lint_checks
24
+
25
+ # can pass in an array, a filename, or a list of checks
26
+ if settings.disabled_lint_checks.class == String
27
+ path = File.expand_path(settings.disabled_lint_checks)
28
+ if File.file? path
29
+ data = File.readlines(path).map {|line| line.chomp }
30
+ data.reject! {|line| line.empty? or line.start_with? '#' }
31
+
32
+ settings.disabled_lint_checks = data
33
+ else
34
+ settings.disabled_lint_checks = settings.disabled_lint_checks.split(',')
35
+ end
36
+ end
37
+
38
+ else
39
+ # this seems... gross, but I don't know a better way to make sure this
40
+ # option exists whether it was passed in or not.
41
+ def settings.disabled_lint_checks
42
+ []
43
+ end
44
+ end
45
+
46
+ end
47
+
48
+ get '/' do
49
+ erb :index
50
+ end
51
+
52
+ post '/validate' do
53
+ logger.info "Validating code from #{request.ip}."
54
+ logger.debug "validating #{request.ip}: #{params['code']}"
55
+
56
+ if request.body.size <= MAXSIZE
57
+ result = validate params['code']
58
+ lint = lint params['code'] if params['lint'] == 'on'
59
+ lint ||= {} # but make sure we have a data object to iterate
60
+
61
+ @code = params['code']
62
+ @message = result[:message]
63
+ @status = result[:status] ? :success : :fail
64
+ @line = result[:line]
65
+ @column = result[:pos]
66
+ @lint_warnings = ! lint.empty?
67
+
68
+ # initial highlighting for the potential syntax error
69
+ if @line
70
+ start = [@line - CONTEXT, 1].max
71
+ initial = {"#{start}-#{@line}" => nil}
72
+ else
73
+ initial = {}
74
+ end
75
+
76
+ # then add all the lint warnings and tooltip
77
+ @highlights = lint.inject(initial) do |acc, item|
78
+ acc.merge({item[:line] => "#{item[:kind].upcase}: #{item[:message]}"})
79
+ end.to_json
80
+
81
+ else
82
+ @message = "Submitted code size is #{request.body.size}, which is larger than the maximum size of #{MAXSIZE}."
83
+ @status = :fail
84
+ logger.error @message
85
+ end
86
+
87
+ erb :result
88
+ end
89
+
90
+ not_found do
91
+ halt 404, "You shall not pass! (page not found)\n"
92
+ end
93
+
94
+ helpers do
95
+
96
+ def validate(data)
97
+ begin
98
+ Puppet[:code] = data
99
+ validation_environment = Puppet.lookup(:current_environment)
100
+
101
+ validation_environment.check_for_reparse
102
+ validation_environment.known_resource_types.clear
103
+
104
+ {:status => true, :message => 'Syntax OK'}
105
+ rescue => detail
106
+ logger.warn detail.message
107
+ err = {:status => false, :message => detail.message}
108
+ err[:line] = detail.line if detail.methods.include? :line
109
+ err[:pos] = detail.pos if detail.methods.include? :pos
110
+ err
111
+ end
112
+ end
113
+
114
+ def lint(data)
115
+ begin
116
+ settings.disabled_lint_checks.each do |check|
117
+ PuppetLint.configuration.send("disable_#{check}")
118
+ end
119
+
120
+ linter = PuppetLint.new
121
+ linter.code = data
122
+ linter.run
123
+ linter.print_problems
124
+ rescue => detail
125
+ logger.warn detail.message
126
+ nil
127
+ end
128
+ end
129
+
130
+
131
+ end
132
+ end
data/public/info.png ADDED
Binary file
@@ -0,0 +1,227 @@
1
+ /* http://prismjs.com/download.html?themes=prism&languages=puppet&plugins=line-highlight+line-numbers */
2
+ /**
3
+ * prism.js default theme for JavaScript, CSS and HTML
4
+ * Based on dabblet (http://dabblet.com)
5
+ * @author Lea Verou
6
+ */
7
+
8
+ code[class*="language-"],
9
+ pre[class*="language-"] {
10
+ color: black;
11
+ background: none;
12
+ text-shadow: 0 1px white;
13
+ font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
14
+ direction: ltr;
15
+ text-align: left;
16
+ white-space: pre;
17
+ word-spacing: normal;
18
+ word-break: normal;
19
+ word-wrap: normal;
20
+ line-height: 1.5;
21
+
22
+ -moz-tab-size: 4;
23
+ -o-tab-size: 4;
24
+ tab-size: 4;
25
+
26
+ -webkit-hyphens: none;
27
+ -moz-hyphens: none;
28
+ -ms-hyphens: none;
29
+ hyphens: none;
30
+ }
31
+
32
+ pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection,
33
+ code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection {
34
+ text-shadow: none;
35
+ background: #b3d4fc;
36
+ }
37
+
38
+ pre[class*="language-"]::selection, pre[class*="language-"] ::selection,
39
+ code[class*="language-"]::selection, code[class*="language-"] ::selection {
40
+ text-shadow: none;
41
+ background: #b3d4fc;
42
+ }
43
+
44
+ @media print {
45
+ code[class*="language-"],
46
+ pre[class*="language-"] {
47
+ text-shadow: none;
48
+ }
49
+ }
50
+
51
+ /* Code blocks */
52
+ pre[class*="language-"] {
53
+ padding: 1em;
54
+ margin: .5em 0;
55
+ overflow: auto;
56
+ }
57
+
58
+ :not(pre) > code[class*="language-"],
59
+ pre[class*="language-"] {
60
+ background: #f5f2f0;
61
+ }
62
+
63
+ /* Inline code */
64
+ :not(pre) > code[class*="language-"] {
65
+ padding: .1em;
66
+ border-radius: .3em;
67
+ white-space: normal;
68
+ }
69
+
70
+ .token.comment,
71
+ .token.prolog,
72
+ .token.doctype,
73
+ .token.cdata {
74
+ color: slategray;
75
+ }
76
+
77
+ .token.punctuation {
78
+ color: #999;
79
+ }
80
+
81
+ .namespace {
82
+ opacity: .7;
83
+ }
84
+
85
+ .token.property,
86
+ .token.tag,
87
+ .token.boolean,
88
+ .token.number,
89
+ .token.constant,
90
+ .token.symbol,
91
+ .token.deleted {
92
+ color: #905;
93
+ }
94
+
95
+ .token.selector,
96
+ .token.attr-name,
97
+ .token.string,
98
+ .token.char,
99
+ .token.builtin,
100
+ .token.inserted {
101
+ color: #690;
102
+ }
103
+
104
+ .token.operator,
105
+ .token.entity,
106
+ .token.url,
107
+ .language-css .token.string,
108
+ .style .token.string {
109
+ color: #a67f59;
110
+ background: hsla(0, 0%, 100%, .5);
111
+ }
112
+
113
+ .token.atrule,
114
+ .token.attr-value,
115
+ .token.keyword {
116
+ color: #07a;
117
+ }
118
+
119
+ .token.function {
120
+ color: #DD4A68;
121
+ }
122
+
123
+ .token.regex,
124
+ .token.important,
125
+ .token.variable {
126
+ color: #e90;
127
+ }
128
+
129
+ .token.important,
130
+ .token.bold {
131
+ font-weight: bold;
132
+ }
133
+ .token.italic {
134
+ font-style: italic;
135
+ }
136
+
137
+ .token.entity {
138
+ cursor: help;
139
+ }
140
+
141
+ pre[data-line] {
142
+ position: relative;
143
+ padding: 1em 0 1em 3em;
144
+ }
145
+
146
+ .line-highlight {
147
+ position: absolute;
148
+ left: 0;
149
+ right: 0;
150
+ padding: inherit 0;
151
+ margin-top: 1em; /* Same as .prism’s padding-top */
152
+
153
+ background: hsla(24, 20%, 50%,.08);
154
+ background: -moz-linear-gradient(left, hsla(24, 20%, 50%,.1) 70%, hsla(24, 20%, 50%,0));
155
+ background: -webkit-linear-gradient(left, hsla(24, 20%, 50%,.1) 70%, hsla(24, 20%, 50%,0));
156
+ background: -o-linear-gradient(left, hsla(24, 20%, 50%,.1) 70%, hsla(24, 20%, 50%,0));
157
+ background: linear-gradient(left, hsla(24, 20%, 50%,.1) 70%, hsla(24, 20%, 50%,0));
158
+
159
+ pointer-events: none;
160
+
161
+ line-height: inherit;
162
+ white-space: pre;
163
+ }
164
+
165
+ .line-highlight:before,
166
+ .line-highlight[data-end]:after {
167
+ content: attr(data-start);
168
+ position: absolute;
169
+ top: .4em;
170
+ left: .6em;
171
+ min-width: 1em;
172
+ padding: 0 .5em;
173
+ background-color: hsla(24, 20%, 50%,.4);
174
+ color: hsl(24, 20%, 95%);
175
+ font: bold 65%/1.5 sans-serif;
176
+ text-align: center;
177
+ vertical-align: .3em;
178
+ border-radius: 999px;
179
+ text-shadow: none;
180
+ box-shadow: 0 1px white;
181
+ }
182
+
183
+ .line-highlight[data-end]:after {
184
+ content: attr(data-end);
185
+ top: auto;
186
+ bottom: .4em;
187
+ }
188
+ pre.line-numbers {
189
+ position: relative;
190
+ padding-left: 3.8em;
191
+ counter-reset: linenumber;
192
+ }
193
+
194
+ pre.line-numbers > code {
195
+ position: relative;
196
+ }
197
+
198
+ .line-numbers .line-numbers-rows {
199
+ position: absolute;
200
+ pointer-events: none;
201
+ top: 0;
202
+ font-size: 100%;
203
+ left: -3.8em;
204
+ width: 3em; /* works for line-numbers below 1000 lines */
205
+ letter-spacing: -1px;
206
+ border-right: 1px solid #999;
207
+
208
+ -webkit-user-select: none;
209
+ -moz-user-select: none;
210
+ -ms-user-select: none;
211
+ user-select: none;
212
+
213
+ }
214
+
215
+ .line-numbers-rows > span {
216
+ pointer-events: none;
217
+ display: block;
218
+ counter-increment: linenumber;
219
+ }
220
+
221
+ .line-numbers-rows > span:before {
222
+ content: counter(linenumber);
223
+ color: #999;
224
+ display: block;
225
+ padding-right: 0.8em;
226
+ text-align: right;
227
+ }