vagrant-hmurca 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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