viaduct-archfile 1.0.0

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: 63f065bff9e330794305661626db5882365e9de7
4
+ data.tar.gz: 2c74bd94f4ed158f077aac456a11fe8490525de6
5
+ SHA512:
6
+ metadata.gz: 1298d266fd0fdff314433c978b2b9ac565a2170ef0e57a9ae1630f94036d92b02c3363b37f23ef77450af1a6643f7fec3827255f85945c8b11c34b61e7b01b78
7
+ data.tar.gz: 379a2bb11cd71be16aa6e245f90391aadd68a562d7bbc429ce81d2d04aa7d84cc48997a9f6e8adad4f9a091aaef82dd0adeefa6e58e48fb50671fd02d46cc98c
data/README.md ADDED
@@ -0,0 +1,27 @@
1
+ # Viaduct Archfile Lint
2
+
3
+ This library is here to help validate the contents of a Viaduct Archfile.
4
+
5
+ ## What is an Archfile?
6
+
7
+ An Archfile is a system specification for an application. It belongs in the root of an application
8
+ and Viaduct will use its contents to determine how it should be deployed when it is set up. They
9
+ are only used for initial provisioning into the Viaduct system.
10
+
11
+ A new Archfile for a running application can be downloaded at anytime.
12
+
13
+ ## What does an Archfile look like?
14
+
15
+ An Archfile is a YAML document which contains a number of properties. The best place to determine
16
+ what it looks like would be to refer to our examples.
17
+
18
+ ## How can I test the validity of an Archfile?
19
+
20
+ To test that your Archfile is appropriate, you can install this library and follow the instructions
21
+ below. Our backend systems also use this library to validate Archfiles so if it passes here, it'll
22
+ pass when you create your application.
23
+
24
+ ```
25
+ $ gem install viaduct-archfile-lint
26
+ $ vdt-archfile-check path/to/Archfile
27
+ ```
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env ruby
2
+ $:.unshift(File.expand_path('../../lib', __FILE__))
3
+ require 'viaduct/archfile'
4
+
5
+ path = ARGV[0] || './Archfile'
6
+ if File.exist?(path)
7
+ archfile = Viaduct::Archfile.new(File.read(path))
8
+ errors = archfile.validate
9
+ if errors.empty?
10
+ puts
11
+ puts " \e[32mCongratulations. That Archfile looks excellent and should work well!\e[0m"
12
+ puts
13
+ puts " Just head over to \e[35mhttps://my.viaduct.io\e[0m to create your new application."
14
+ puts " Don't forget to add your Archfile to your repository so we can find it."
15
+ puts
16
+ else
17
+ puts
18
+ puts " \e[31mOh no. It seems there's a problem with your Archfile!\e[0m"
19
+ puts
20
+ errors.each do |field, value|
21
+ puts " * #{field ? field + ' ' : nil}\e[33m#{value}\e[0m"
22
+ end
23
+ puts
24
+ end
25
+ else
26
+ $stderr.puts "\e[31m!! Couldn't find Viaduct Archfile at #{path}\e[0m"
27
+ exit 1
28
+ end
@@ -0,0 +1,196 @@
1
+ require 'yaml'
2
+
3
+ module Viaduct
4
+ class Archfile
5
+
6
+ APPLICATION_STACKS = ['ruby2.0']
7
+ SHARED_DATABASE_TYPES = ['mysql']
8
+ START_DETECTOR_MODULES = ['none', 'log_string', 'timer']
9
+ COMMAND_EVENTS = ['build', 'start', 'firstrun']
10
+
11
+ PATH_REGEX = /\A[a-z0-9\_\-\/\.]+\z/
12
+
13
+
14
+ #
15
+ # Create a new Archfile object from raw yaml
16
+ #
17
+ def initialize(yaml)
18
+ @yaml = yaml
19
+ end
20
+
21
+ #
22
+ # Store errors
23
+ #
24
+ def errors
25
+ @errors ||= []
26
+ end
27
+
28
+ #
29
+ # Store the current namespace we're working in
30
+ #
31
+ def namespace(hash, *ns)
32
+ @current_hash = hash
33
+ @current_namespace = ns
34
+ end
35
+
36
+ #
37
+ # Add an error
38
+ #
39
+ def add_error(key, message)
40
+ errors << [key.nil? ? nil : "#{@current_namespace.join('.')}.#{key}", message]
41
+ end
42
+
43
+ #
44
+ # Validate that the object is valid, returning an array of errors
45
+ # or an empty array if there are no errors.
46
+ #
47
+ def validate
48
+ @errors = []
49
+
50
+ #
51
+ # Load the YAML
52
+ #
53
+ begin
54
+ spec = YAML.load(@yaml)
55
+ rescue Psych::SyntaxError => e
56
+ errors << [nil, "YAML document could not be read (#{e.message})"]
57
+ return @errors
58
+ end
59
+
60
+ #
61
+ # Check settings
62
+ #
63
+ namespace spec['settings'], 'settings'
64
+ ensure_boolean('sleep_inactive_web_processes')
65
+ ensure_boolean('serve_static_files')
66
+ ensure_matches(/\A[a-z0-9\_\-\/]+\z/, 'document_root')
67
+
68
+ #
69
+ # Check that we have some processes to begin with
70
+ #
71
+ unless spec['processes'].is_a?(Array) && spec['processes'].length > 0
72
+ add_error nil, "You must have at least one process"
73
+ end
74
+
75
+ #
76
+ # Check processes
77
+ #
78
+ if spec['processes'].is_a?(Array)
79
+ spec['processes'].each_with_index do |process, index|
80
+ namespace process, 'processes', index
81
+ ensure_string('command')
82
+ ensure_inclusion(APPLICATION_STACKS, 'stack')
83
+ ensure_integer('quantity')
84
+ ensure_matches(PATH_REGEX, 'name')
85
+ ensure_integer('kill_after') if process['kill_after']
86
+ if sm = process['start_monitor']
87
+ namespace sm, 'processes', index, 'start_monitor'
88
+ ensure_inclusion(START_DETECTOR_MODULES, 'module')
89
+ ensure_integer('timer') if sm['module'] == 'timer'
90
+ ensure_string('string') if sm['module'] == 'log_string'
91
+ end
92
+ end
93
+ end
94
+
95
+ #
96
+ # Check shared databases
97
+ #
98
+ if spec['shared_databases'].is_a?(Array)
99
+ spec['shared_databases'].each_with_index do |db, index|
100
+ namespace db, 'shared_databases', index
101
+ ensure_inclusion(SHARED_DATABASE_TYPES, 'type')
102
+ ensure_string('label')
103
+ end
104
+ end
105
+
106
+ #
107
+ # Check Environment Variables
108
+ #
109
+ if spec['environment_variables'].is_a?(Array)
110
+ spec['environment_variables'].each_with_index do |ev, index|
111
+ namespace ev, 'environment_variables', index
112
+ ensure_string('key', 'value')
113
+ end
114
+ end
115
+
116
+ #
117
+ # Check persistent directories
118
+ #
119
+ if spec['persistent_directories'].is_a?(Array)
120
+ spec['persistent_directories'].each_with_index do |pd, index|
121
+ namespace pd, 'persistent_directories', index
122
+ ensure_matches(PATH_REGEX, 'path')
123
+ end
124
+ end
125
+
126
+ #
127
+ # Check commands
128
+ #
129
+ if spec['commands'].is_a?(Array)
130
+ spec['commands'].each_with_index do |command, index|
131
+ namespace command, 'commands', index
132
+ ensure_inclusion APPLICATION_STACKS, 'stack'
133
+ ensure_inclusion COMMAND_EVENTS, 'event'
134
+ ensure_string 'command'
135
+ ensure_integer 'success_exit_code'
136
+ end
137
+ end
138
+
139
+ #
140
+ # Check config files
141
+ #
142
+ if spec['config_files'].is_a?(Array)
143
+ spec['config_files'].each_with_index do |cf, index|
144
+ namespace cf, 'config_files', index
145
+ ensure_matches PATH_REGEX, 'path'
146
+ ensure_string 'content'
147
+ end
148
+ end
149
+
150
+ errors
151
+ end
152
+
153
+ private
154
+
155
+ def value_for(item)
156
+ @current_hash[item]
157
+ end
158
+
159
+ def ensure_boolean(*items)
160
+ items.each do |item|
161
+ value = value_for(item)
162
+ add_error item, "must be a boolean" unless value.is_a?(TrueClass) || value.is_a?(FalseClass)
163
+ end
164
+ end
165
+
166
+ def ensure_string(*items)
167
+ items.each do |item|
168
+ value = value_for(item)
169
+ add_error item, "must be a string" unless value.is_a?(String) && value.length > 0
170
+ end
171
+ end
172
+
173
+ def ensure_matches(regex, *items)
174
+ items.each do |item|
175
+ value = value_for(item)
176
+ unless value.is_a?(String) && value =~ regex
177
+ add_error item, "must match #{regex.to_s}"
178
+ end
179
+ end
180
+ end
181
+
182
+ def ensure_integer(*items)
183
+ items.each do |item|
184
+ value = value_for(item)
185
+ add_error item, "must be a number" unless value.is_a?(Fixnum)
186
+ end
187
+ end
188
+
189
+ def ensure_inclusion(options, *items)
190
+ items.each do |item|
191
+ add_error item, "must be one of #{options}" unless options.include?(value_for(item))
192
+ end
193
+ end
194
+
195
+ end
196
+ end
metadata ADDED
@@ -0,0 +1,48 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: viaduct-archfile
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Adam Cooke
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-01-28 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: A validation tool for checking the validity of a Viaduct Archfile
14
+ email:
15
+ - adam@viaduct.io
16
+ executables:
17
+ - vdt-archfile-check
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - bin/vdt-archfile-check
22
+ - lib/viaduct/archfile.rb
23
+ - README.md
24
+ homepage: http://viaduct.io
25
+ licenses: []
26
+ metadata: {}
27
+ post_install_message:
28
+ rdoc_options: []
29
+ require_paths:
30
+ - lib
31
+ required_ruby_version: !ruby/object:Gem::Requirement
32
+ requirements:
33
+ - - '>='
34
+ - !ruby/object:Gem::Version
35
+ version: '0'
36
+ required_rubygems_version: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ requirements: []
42
+ rubyforge_project:
43
+ rubygems_version: 2.0.3
44
+ signing_key:
45
+ specification_version: 4
46
+ summary: A validation tool for checking the validity of a Viaduct Archfile
47
+ test_files: []
48
+ has_rdoc: