vagrant-hmurca 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +20 -0
- data/Gemfile +9 -0
- data/LICENSE.txt +22 -0
- data/README.md +31 -0
- data/Rakefile +10 -0
- data/Vagrantfile +15 -0
- data/dot_gitignore +2 -0
- data/hmurca.conf +12 -0
- data/hmurca.conf.sample +32 -0
- data/lib/vagrant-hmurca.rb +1 -0
- data/lib/vagrant/hmurca.rb +33 -0
- data/lib/vagrant/hmurca/command.rb +75 -0
- data/lib/vagrant/hmurca/config_parser.rb +225 -0
- data/lib/vagrant/hmurca/errors.rb +96 -0
- data/lib/vagrant/hmurca/templates/Vagrantfile +15 -0
- data/lib/vagrant/hmurca/templates/dot_gitignore +2 -0
- data/lib/vagrant/hmurca/templates/hmurca.conf.sample.tt +32 -0
- data/lib/vagrant/hmurca/vagrantfile.rb +36 -0
- data/lib/vagrant/hmurca/version.rb +5 -0
- data/test/config_parser_test.rb +590 -0
- data/test/helper.rb +6 -0
- data/test/vagrant_command_test.rb +69 -0
- data/test/version_test.rb +7 -0
- data/vagrant-hmurca.gemspec +26 -0
- metadata +142 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 6e1d3d8b8c0364076264a98dfb745de017382bae
|
4
|
+
data.tar.gz: 820fe62cfe4b5ccbe417c61d0867ca08e3401f58
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1d11604f05257f785cb599128a9a4b4f1bd0709579163ca15d997e793c62e33aaa06c7c7fc75dacecdd8f3cdf9df5ded0cd383bd3376a82a9adfff79143bebfb
|
7
|
+
data.tar.gz: ea182236bd13693bcbf1d79077acfb558c9e01116c5b0913b0ee4553583206bfd46d5eab7bc157e9957cd83f1337238576a397032b4388c19e118cc747600007
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Kris Kovalik
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# Hmurca's Vagrant Kit
|
2
|
+
|
3
|
+
This toolkit (codename *Hobo*) is a *Vagrant* plugin that wraps and simplifies
|
4
|
+
building of *Hmurca* powered development formations.
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
Install this gem as a *Vagrant* plugin.
|
9
|
+
|
10
|
+
$ vagrant plugin install vagrant-hmurca
|
11
|
+
|
12
|
+
## Usage
|
13
|
+
|
14
|
+
Check project documentation [here](http://docs.hmurca.com/en/latest/vagrant-hmurca.html).
|
15
|
+
|
16
|
+
## End-to-end testing
|
17
|
+
|
18
|
+
Because there's not mean to run end-to-end test automatically (for example Vagrant
|
19
|
+
doesn't work on drone.io that we use for CI testing), you should test it manually
|
20
|
+
before making any changes. There's a test `Vagrantfile` and `hmurca.conf` in project
|
21
|
+
root directory, use them to bring the formation up and check if everything works as
|
22
|
+
expected. Run the following from project root directory:
|
23
|
+
|
24
|
+
$ bundle exec vagrant up
|
25
|
+
|
26
|
+
## Contributing
|
27
|
+
|
28
|
+
1. Work on your changes in a feature branch.
|
29
|
+
2. Make sure that tests are passing.
|
30
|
+
3. Send a pull request.
|
31
|
+
4. Wait for feedback.
|
data/Rakefile
ADDED
data/Vagrantfile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# -*- mode: ruby -*-
|
2
|
+
# vi: set ft=ruby :
|
3
|
+
|
4
|
+
# WARNING: Never ever edit this file if you want Hmurca Kit to work properly!
|
5
|
+
|
6
|
+
ui = Vagrant::UI::Colored.new
|
7
|
+
|
8
|
+
begin
|
9
|
+
require 'vagrant-hmurca'
|
10
|
+
Vagrant::Hmurca.configure!
|
11
|
+
rescue LoadError => err
|
12
|
+
ui.error("Oops! Looks like `vagrant-hmurca' plugin is not installed!")
|
13
|
+
ui.error("Execute `vagrant plugin install vagrant-hmurca` to fix this error...")
|
14
|
+
exit(1)
|
15
|
+
end
|
data/dot_gitignore
ADDED
data/hmurca.conf
ADDED
data/hmurca.conf.sample
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# hmurca.conf - The Hmurca Vagrant Kit configuration file.
|
2
|
+
#
|
3
|
+
# If this file is named `hmurca.conf.sample`, copy it to `hmurca.conf`
|
4
|
+
# and adjust settings specific for your host machine or your own preferences.
|
5
|
+
|
6
|
+
# General setup
|
7
|
+
#-------------------------------------------------------------------------------
|
8
|
+
|
9
|
+
# Domain name used by this formation.
|
10
|
+
domain example
|
11
|
+
|
12
|
+
# Name of the base box from Vagrant Cloud.
|
13
|
+
base-box hmurca/debian75-x64
|
14
|
+
|
15
|
+
# Configure synchronized folders from host to guests...
|
16
|
+
sync-folder . /vagrant
|
17
|
+
|
18
|
+
# Use Network File System to share folders?
|
19
|
+
use-nfs yes
|
20
|
+
|
21
|
+
# Nodes configuration...
|
22
|
+
#-------------------------------------------------------------------------------
|
23
|
+
|
24
|
+
node
|
25
|
+
# Short host name of the node.
|
26
|
+
name all-in-one
|
27
|
+
# The number of virtual processors.
|
28
|
+
cpus 2
|
29
|
+
# The number of virtual memory limit.
|
30
|
+
memory 1024
|
31
|
+
# Configure which ports to forward from guest to host...
|
32
|
+
forward-port 80 8080
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'vagrant/hmurca'
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require "vagrant"
|
2
|
+
require "booby"
|
3
|
+
|
4
|
+
module Vagrant
|
5
|
+
module Hmurca
|
6
|
+
require "vagrant/hmurca/version"
|
7
|
+
require "vagrant/hmurca/errors"
|
8
|
+
require "vagrant/hmurca/config_parser"
|
9
|
+
|
10
|
+
# Internal: Hmurca vagrant plugin.
|
11
|
+
class Plugin < Vagrant.plugin(2)
|
12
|
+
name "Hmurca"
|
13
|
+
description "Hmurka's Vagrant Kit"
|
14
|
+
|
15
|
+
command "hmurca", primary: true do
|
16
|
+
require "vagrant/hmurca/command"
|
17
|
+
Command
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Public: Sets up vagrant configuration.
|
22
|
+
def self.configure!
|
23
|
+
begin
|
24
|
+
config_file = File.join(Dir.pwd, "hmurca.conf")
|
25
|
+
$CONF = ConfigParser.parse_file(config_file)
|
26
|
+
load(File.expand_path("../hmurca/vagrantfile.rb", __FILE__))
|
27
|
+
rescue ParserError, Errno::ENOENT => err
|
28
|
+
$stderr.write("ERROR: #{err.to_s}\n")
|
29
|
+
exit(1)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require "thor"
|
2
|
+
|
3
|
+
module Vagrant
|
4
|
+
module Hmurca
|
5
|
+
# Internal: Files generator for hmurca default command.
|
6
|
+
class Generator < Thor::Group
|
7
|
+
include Thor::Actions
|
8
|
+
|
9
|
+
argument :domain
|
10
|
+
argument :project_root, :optional => true, :default => "."
|
11
|
+
|
12
|
+
def self.source_root
|
13
|
+
File.expand_path("../templates", __FILE__)
|
14
|
+
end
|
15
|
+
|
16
|
+
def create_project_root
|
17
|
+
empty_directory(project_root)
|
18
|
+
end
|
19
|
+
|
20
|
+
def create_hmurca_conf_sample
|
21
|
+
target = File.join(project_root, "hmurca.conf.sample")
|
22
|
+
template("hmurca.conf.sample.tt", target)
|
23
|
+
end
|
24
|
+
|
25
|
+
def copy_dot_gitignore
|
26
|
+
target = File.join(project_root, ".gitignore")
|
27
|
+
copy_file("dot_gitignore", target)
|
28
|
+
end
|
29
|
+
|
30
|
+
def copy_vagrantfile
|
31
|
+
target = File.join(project_root, "Vagrantfile")
|
32
|
+
copy_file("Vagrantfile", target)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Internal: Hmurca command that generates project scaffold.
|
37
|
+
class Command < Vagrant.plugin(2, :command)
|
38
|
+
def self.synopsis
|
39
|
+
"initializes hmurca-powered project"
|
40
|
+
end
|
41
|
+
|
42
|
+
def execute
|
43
|
+
argv = parse_options(option_parser)
|
44
|
+
|
45
|
+
if argv.empty?
|
46
|
+
@env.ui.error "You must specify domain name for development formation."
|
47
|
+
exit(1)
|
48
|
+
end
|
49
|
+
|
50
|
+
if argv.size > 2
|
51
|
+
@env.ui.error "Too many actual arguments."
|
52
|
+
exit(1)
|
53
|
+
end
|
54
|
+
|
55
|
+
Generator.start(argv)
|
56
|
+
end
|
57
|
+
|
58
|
+
def option_parser
|
59
|
+
OptionParser.new do |o|
|
60
|
+
o.banner = "Usage: vagrant hmurca DOMAIN [ROOT]"
|
61
|
+
|
62
|
+
o.on("-h", "--help", "Print this help.") do
|
63
|
+
safe_puts(o.help)
|
64
|
+
exit(0)
|
65
|
+
end
|
66
|
+
|
67
|
+
o.on("-p", "--plugin-version", "Print version of installed Hmurca Kit.") do
|
68
|
+
safe_puts("Hmurca Vagrant Kit #{Vagrant::Hmurca::VERSION}")
|
69
|
+
exit(0)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,225 @@
|
|
1
|
+
module Vagrant
|
2
|
+
module Hmurca
|
3
|
+
# Public: Processor that handles node definition groups.
|
4
|
+
class NodeGroupProcessor
|
5
|
+
ARITY = {
|
6
|
+
'name' => 1,
|
7
|
+
'cpus' => 1,
|
8
|
+
'memory' => 1,
|
9
|
+
'forward-port' => 2,
|
10
|
+
}
|
11
|
+
|
12
|
+
attr_reader :name, :cpus, :memory, :forward_ports
|
13
|
+
|
14
|
+
def initialize(line_no, name=nil)
|
15
|
+
@name = name
|
16
|
+
@forward_ports = {}
|
17
|
+
|
18
|
+
return unless name
|
19
|
+
raise InvalidNodeNameError.new(name, line_no) unless valid_name?(name)
|
20
|
+
end
|
21
|
+
|
22
|
+
def process(line_no, cmd, *args)
|
23
|
+
case cmd
|
24
|
+
when "name"
|
25
|
+
n = args.first
|
26
|
+
raise InvalidNodeNameError.new(n, line_no) unless valid_name?(n)
|
27
|
+
@name = n
|
28
|
+
when "cpus"
|
29
|
+
@cpus = parse_int(args.first, line_no)
|
30
|
+
when "memory"
|
31
|
+
@memory = parse_int(args.first, line_no)
|
32
|
+
when "forward-port"
|
33
|
+
guest, host = parse_int(args[0], line_no), parse_int(args[1], line_no)
|
34
|
+
|
35
|
+
if @forward_ports[host]
|
36
|
+
raise NodeForwardPortDuplicatedError.new(host)
|
37
|
+
end
|
38
|
+
|
39
|
+
@forward_ports[host] = guest
|
40
|
+
else
|
41
|
+
return false
|
42
|
+
end
|
43
|
+
|
44
|
+
true
|
45
|
+
end
|
46
|
+
|
47
|
+
# Internal: Validates post-parsing constraints, like presence checking, etc.
|
48
|
+
#
|
49
|
+
# Returns itself.
|
50
|
+
def validate!
|
51
|
+
raise NoNodeNameSpecifiedError unless self.name
|
52
|
+
raise NoNodeCpusCountSpecifiedError.new(name) unless self.cpus
|
53
|
+
raise NoNodeMemorySizeSpecifiedError.new(name) unless self.memory
|
54
|
+
|
55
|
+
return self
|
56
|
+
end
|
57
|
+
|
58
|
+
# Internal: Checks if given node name is valid.
|
59
|
+
#
|
60
|
+
# name - The String node name to check.
|
61
|
+
#
|
62
|
+
# Return true if node name is valid.
|
63
|
+
def valid_name?(name)
|
64
|
+
name =~ /^[\w\d\-]+$/
|
65
|
+
end
|
66
|
+
|
67
|
+
# Internal: Parses given string value and converts it to integer if
|
68
|
+
# it's possible. If given value is not a valid integer, it raises
|
69
|
+
# an error.
|
70
|
+
#
|
71
|
+
# v - The String value to covnert.
|
72
|
+
# line_no - The Integer number of the current parsed line.
|
73
|
+
#
|
74
|
+
# Returns converted int value.
|
75
|
+
# Raises InvalidIntegerValueError if value can't be converted.
|
76
|
+
def parse_int(v, line_no)
|
77
|
+
v_int = v.to_i
|
78
|
+
raise InvalidIntegerValueError.new(v, line_no) if v_int.to_s != v
|
79
|
+
v_int
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# Public: Processor for top level configuration.
|
84
|
+
class GeneralProcessor
|
85
|
+
ARITY = {
|
86
|
+
'domain' => 1,
|
87
|
+
'base-box' => 1,
|
88
|
+
'sync-folder' => 2,
|
89
|
+
'use-nfs' => 1
|
90
|
+
}
|
91
|
+
|
92
|
+
attr_reader :domain, :base_box, :sync_folders, :use_nfs, :nodes
|
93
|
+
|
94
|
+
def initialize
|
95
|
+
@nodes = []
|
96
|
+
@sync_folders = []
|
97
|
+
end
|
98
|
+
|
99
|
+
def process(line_no, cmd, *args)
|
100
|
+
case cmd
|
101
|
+
when 'domain'
|
102
|
+
d = args.first
|
103
|
+
raise InvalidDomainNameError.new(d, line_no) unless valid_domain?(d)
|
104
|
+
@domain = d
|
105
|
+
when 'base-box'
|
106
|
+
b = args.first
|
107
|
+
@base_box = b
|
108
|
+
when 'sync-folder'
|
109
|
+
host, guest = *args
|
110
|
+
|
111
|
+
unless File.directory?(host)
|
112
|
+
raise SyncedFolderNotFoundError.new(host, line_no)
|
113
|
+
end
|
114
|
+
|
115
|
+
@sync_folders << [host, guest]
|
116
|
+
when 'use-nfs'
|
117
|
+
@use_nfs = parse_bool(args.first, line_no)
|
118
|
+
when 'node'
|
119
|
+
if args.size > 1
|
120
|
+
raise Booby::InvalidNumberOfParametersError.new(
|
121
|
+
"0 or 1", args.size, cmd, line_no
|
122
|
+
)
|
123
|
+
end
|
124
|
+
|
125
|
+
@nodes << (p = NodeGroupProcessor.new(line_no, *args))
|
126
|
+
return p
|
127
|
+
else
|
128
|
+
return false
|
129
|
+
end
|
130
|
+
|
131
|
+
true
|
132
|
+
end
|
133
|
+
|
134
|
+
# Public: Produces reverse domain name to use as a box prefix.
|
135
|
+
def name_as_prefix
|
136
|
+
return self.domain.split('.').reverse.join('.')
|
137
|
+
end
|
138
|
+
|
139
|
+
# Internal: Validates post-parsing constraints, like presence checking, etc.
|
140
|
+
#
|
141
|
+
# Returns itself.
|
142
|
+
def validate!
|
143
|
+
raise NoDomainSpecifiedError unless self.domain
|
144
|
+
|
145
|
+
# Validate each node separately...
|
146
|
+
self.nodes.each(&:validate!)
|
147
|
+
|
148
|
+
# Check for duplicated nodes...
|
149
|
+
# XXX: Yes this way of checking might be slow, but who cares with max
|
150
|
+
# 10 defined nodes?
|
151
|
+
unique_nodes = {}
|
152
|
+
self.nodes.each do |node|
|
153
|
+
name = node.name
|
154
|
+
raise NodeDuplicatedError.new(name) if unique_nodes[name]
|
155
|
+
unique_nodes[name] = true
|
156
|
+
end
|
157
|
+
|
158
|
+
# Check for duplicated forward ports...
|
159
|
+
# XXX: Same here in terms of efficiency.
|
160
|
+
unique_ports = {}
|
161
|
+
self.nodes.each do |node|
|
162
|
+
node.forward_ports.keys.each do |port|
|
163
|
+
raise NodeForwardPortDuplicatedError.new(port) if unique_ports[port]
|
164
|
+
unique_ports[port] = true
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
return self
|
169
|
+
end
|
170
|
+
|
171
|
+
# Internal: Checks weather given domain name is valid or not.
|
172
|
+
#
|
173
|
+
# domain - The String domain name to check.
|
174
|
+
#
|
175
|
+
# Returns true if domain name is valid.
|
176
|
+
def valid_domain?(domain)
|
177
|
+
domain =~ /^[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?$/ix
|
178
|
+
end
|
179
|
+
|
180
|
+
# Internal: Converts given string value to boolean. If value isn't one
|
181
|
+
# of 'yes' or 'no', then it raises an error.
|
182
|
+
#
|
183
|
+
# v - The String value to covnert.
|
184
|
+
# line_no - The Integer number of the current parsed line.
|
185
|
+
#
|
186
|
+
# Returns true if value equals 'yes', false if 'no'.
|
187
|
+
# Raises InvalidBooleanValueError if value can't be converted.
|
188
|
+
def parse_bool(v, line_no)
|
189
|
+
case v
|
190
|
+
when "yes"
|
191
|
+
true
|
192
|
+
when "no"
|
193
|
+
false
|
194
|
+
else
|
195
|
+
raise InvalidBooleanValueError.new(v, line_no)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
# Public: Global entry point to config parser features.
|
201
|
+
module ConfigParser
|
202
|
+
PROCESSOR = GeneralProcessor
|
203
|
+
|
204
|
+
# Public: Loads given file and parses it.
|
205
|
+
#
|
206
|
+
# fname - The String name of the config file.
|
207
|
+
#
|
208
|
+
# Returns filled processor.
|
209
|
+
def self.parse_file(fname)
|
210
|
+
p = Booby.open(fname)
|
211
|
+
p.parse_with(PROCESSOR).validate!
|
212
|
+
end
|
213
|
+
|
214
|
+
# Public: Parses given source of the config file.
|
215
|
+
#
|
216
|
+
# str - The String source to parse.
|
217
|
+
#
|
218
|
+
# Returns filled processor.
|
219
|
+
def self.parse_string(str)
|
220
|
+
p = Booby.prepare(str)
|
221
|
+
p.parse_with(PROCESSOR).validate!
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|