vagrant-hmurca 0.1.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.
@@ -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
@@ -0,0 +1,20 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ \#*
19
+ .\#*
20
+ .vagrant
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ group :development do
4
+ gem "vagrant", :git => "https://github.com/mitchellh/vagrant.git", :tag => "v1.6.3"
5
+ end
6
+
7
+ group :plugins do
8
+ gemspec
9
+ end
@@ -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.
@@ -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.
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.libs.push "lib"
6
+ t.pattern = "test/*_test.rb"
7
+ t.verbose = false
8
+ end
9
+
10
+ task :default => :test
@@ -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
@@ -0,0 +1,2 @@
1
+ .vagrant
2
+ *.conf.sample
@@ -0,0 +1,12 @@
1
+ # hmurca.conf - Testing configuration.
2
+
3
+ domain example.dev
4
+ base-box cargomedia/debian-7-amd64-plain
5
+ sync-folder . /vagrant
6
+ use-nfs yes
7
+
8
+ node
9
+ name all-in-one
10
+ cpus 1
11
+ memory 1024
12
+ forward-port 80 8080
@@ -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