viaduct-archfile 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +27 -0
- data/bin/vdt-archfile-check +28 -0
- data/lib/viaduct/archfile.rb +196 -0
- metadata +48 -0
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:
|