zergrush 0.0.1

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,227 @@
1
+ Feature: Hive
2
+ When I init, verify list and import hive configs
3
+ As a CLI
4
+ I want to see success
5
+
6
+ Scenario: Initializing hive
7
+ When I run `zerg init`
8
+ Then the following files should exist:
9
+ | .hive/helloworld.ke | .hive/helloaws.ke |
10
+ Then the file ".hive/helloworld.ke" should contain:
11
+ """
12
+ {
13
+ "instances": 3,
14
+ "tasks": [
15
+ {
16
+ "type": "shell",
17
+ "inline": "echo \"ZERG RUSH!\""
18
+ }
19
+ ],
20
+ "vm": {
21
+ "driver": {
22
+ "drivertype": "vagrant",
23
+ "providertype": "virtualbox",
24
+ "provider_options": [
25
+ "virtualbox.gui = false",
26
+ "virtualbox.memory = 256",
27
+ "# adjust for DNS weirdness in ubuntu 12.04",
28
+ "virtualbox.customize ['modifyvm', :id, '--natdnsproxy1', 'off']",
29
+ "virtualbox.customize ['modifyvm', :id, '--natdnshostresolver1', 'off']",
30
+ "# set virtio type on the NIC driver. Better performance for large traffic bursts",
31
+ "virtualbox.customize ['modifyvm', :id, '--nictype1', 'virtio']",
32
+ "virtualbox.customize ['modifyvm', :id, '--nictype2', 'virtio']",
33
+ "virtualbox.customize ['modifyvm', :id, '--nictype3', 'virtio']"
34
+ ]
35
+ },
36
+ "basebox": "http://files.vagrantup.com/precise32.box",
37
+ "private_network": true
38
+ }
39
+ }
40
+ """
41
+
42
+ Then the file ".hive/helloaws.ke" should contain:
43
+ """
44
+ {
45
+ "instances": 3,
46
+ "tasks": [
47
+ {
48
+ "type": "shell",
49
+ "inline": "echo \"ZERG RUSH PRIME!\""
50
+ }
51
+ ],
52
+ "vm": {
53
+ "driver": {
54
+ "drivertype": "vagrant",
55
+ "providertype": "aws",
56
+ "provider_options": [
57
+ "aws.instance_type = 't1.micro'",
58
+ "aws.access_key_id = \"#{ENV['AWS_ACCESS_KEY_ID']}\"",
59
+ "aws.secret_access_key = \"#{ENV['AWS_SECRET_ACCESS_KEY']}\"",
60
+ "aws.keypair_name = \"#{ENV['AWS_KEY_PAIR']}\"",
61
+ "aws.ami = 'ami-3fec7956'",
62
+ "aws.region = 'us-east-1'",
63
+ "aws.security_groups = [ \"#{ENV['AWS_SECURITY_GROUP']}\" ]",
64
+ "override.ssh.username = 'ubuntu'",
65
+ "override.ssh.private_key_path = \"#{ENV['AWS_PRIVATE_KEY_PATH']}\""
66
+ ]
67
+ },
68
+ "basebox": "https://github.com/mitchellh/vagrant-aws/raw/master/dummy.box",
69
+ "private_network": false
70
+ }
71
+ }
72
+ """
73
+ And the exit status should be 0
74
+
75
+ @no-clobber
76
+ Scenario: Verifying hive
77
+ When I run `zerg hive verify`
78
+ Then the output should contain:
79
+ """
80
+ SUCCESS!
81
+ """
82
+ And the exit status should be 0
83
+
84
+ When I run `zerg hive list`
85
+ Then the output should contain:
86
+ """
87
+ 2 tasks in current hive:
88
+ [
89
+ [0] "helloaws",
90
+ [1] "helloworld"
91
+ ]
92
+ """
93
+ And the exit status should be 0
94
+
95
+ @no-clobber
96
+ Scenario: Importing a hive task
97
+ Given a file named "arubatask.ke" with:
98
+ """
99
+ {
100
+ "instances": 1,
101
+ "tasks": [
102
+ {
103
+ "type": "shell",
104
+ "inline": "echo \"ARRRRRRRUUUUUBAAAAAAAA!\""
105
+ }
106
+ ],
107
+ "vm": {
108
+ "driver": {
109
+ "drivertype": "vagrant",
110
+ "providertype": "aws",
111
+ "provider_options": [
112
+ "aws.instance_type = 't1.micro'"
113
+ ]
114
+ },
115
+ "basebox": "https://github.com/mitchellh/vagrant-aws/raw/master/dummy.box",
116
+ "private_network": false
117
+ }
118
+ }
119
+ """
120
+
121
+ When I run `zerg hive import arubatask.ke`
122
+ Then the output should contain:
123
+ """
124
+ SUCCESS!
125
+ """
126
+ And the exit status should be 0
127
+
128
+ When I run `zerg hive import arubatask.ke`
129
+ Then the output should contain:
130
+ """
131
+ ERROR: 'arubatask.ke' already exists in hive!
132
+ """
133
+ And the exit status should be 1
134
+
135
+ When I run `zerg hive import arubatask.ke --force`
136
+ Then the output should contain:
137
+ """
138
+ SUCCESS!
139
+ """
140
+ And the exit status should be 0
141
+
142
+ @no-clobber
143
+ Scenario: Listing hive tasks
144
+ When I run `zerg hive list`
145
+ Then the output should contain:
146
+ """
147
+ 3 tasks in current hive:
148
+ [
149
+ [0] "arubatask",
150
+ [1] "helloaws",
151
+ [2] "helloworld"
152
+ ]
153
+ """
154
+ And the exit status should be 0
155
+
156
+ Scenario: Overriding hive location
157
+ Given a directory named "overriden/hive/dir"
158
+ Given I set the environment variables to:
159
+ | variable | value |
160
+ | HIVE_CWD | ./overriden/hive/dir |
161
+ When I run `zerg init`
162
+ Then the following files should exist:
163
+ | overriden/hive/dir/.hive/helloworld.ke | overriden/hive/dir/.hive/helloaws.ke |
164
+ Then the file "overriden/hive/dir/.hive/helloworld.ke" should contain:
165
+ """
166
+ {
167
+ "instances": 3,
168
+ "tasks": [
169
+ {
170
+ "type": "shell",
171
+ "inline": "echo \"ZERG RUSH!\""
172
+ }
173
+ ],
174
+ "vm": {
175
+ "driver": {
176
+ "drivertype": "vagrant",
177
+ "providertype": "virtualbox",
178
+ "provider_options": [
179
+ "virtualbox.gui = false",
180
+ "virtualbox.memory = 256",
181
+ "# adjust for DNS weirdness in ubuntu 12.04",
182
+ "virtualbox.customize ['modifyvm', :id, '--natdnsproxy1', 'off']",
183
+ "virtualbox.customize ['modifyvm', :id, '--natdnshostresolver1', 'off']",
184
+ "# set virtio type on the NIC driver. Better performance for large traffic bursts",
185
+ "virtualbox.customize ['modifyvm', :id, '--nictype1', 'virtio']",
186
+ "virtualbox.customize ['modifyvm', :id, '--nictype2', 'virtio']",
187
+ "virtualbox.customize ['modifyvm', :id, '--nictype3', 'virtio']"
188
+ ]
189
+ },
190
+ "basebox": "http://files.vagrantup.com/precise32.box",
191
+ "private_network": true
192
+ }
193
+ }
194
+ """
195
+
196
+ Then the file "overriden/hive/dir/.hive/helloaws.ke" should contain:
197
+ """
198
+ {
199
+ "instances": 3,
200
+ "tasks": [
201
+ {
202
+ "type": "shell",
203
+ "inline": "echo \"ZERG RUSH PRIME!\""
204
+ }
205
+ ],
206
+ "vm": {
207
+ "driver": {
208
+ "drivertype": "vagrant",
209
+ "providertype": "aws",
210
+ "provider_options": [
211
+ "aws.instance_type = 't1.micro'",
212
+ "aws.access_key_id = \"#{ENV['AWS_ACCESS_KEY_ID']}\"",
213
+ "aws.secret_access_key = \"#{ENV['AWS_SECRET_ACCESS_KEY']}\"",
214
+ "aws.keypair_name = \"#{ENV['AWS_KEY_PAIR']}\"",
215
+ "aws.ami = 'ami-3fec7956'",
216
+ "aws.region = 'us-east-1'",
217
+ "aws.security_groups = [ \"#{ENV['AWS_SECURITY_GROUP']}\" ]",
218
+ "override.ssh.username = 'ubuntu'",
219
+ "override.ssh.private_key_path = \"#{ENV['AWS_PRIVATE_KEY_PATH']}\""
220
+ ]
221
+ },
222
+ "basebox": "https://github.com/mitchellh/vagrant-aws/raw/master/dummy.box",
223
+ "private_network": false
224
+ }
225
+ }
226
+ """
227
+ And the exit status should be 0
@@ -0,0 +1,4 @@
1
+ require 'aruba/cucumber'
2
+ Before do
3
+ @aruba_timeout_seconds = 120
4
+ end
@@ -0,0 +1,31 @@
1
+ Feature: Tasks
2
+ When I clean a task
3
+ As a CLI
4
+ I want to see success
5
+
6
+ @no-clobber
7
+ Scenario: Cleaning a task
8
+ When I run `zerg init`
9
+ When I run `zerg clean helloworld`
10
+ Then the output should contain:
11
+ """
12
+ SUCCESS!
13
+ """
14
+ And the exit status should be 0
15
+
16
+ Scenario: Cleaning a task that does not exist
17
+ When I run `zerg init`
18
+ When I run `zerg clean HRRGRHBGRGHLURGH`
19
+ Then the output should contain:
20
+ """
21
+ ERROR: Task HRRGRHBGRGHLURGH not found in current hive!
22
+ """
23
+ And the exit status should be 1
24
+
25
+ Scenario: Cleaning a task without hive
26
+ When I run `zerg clean helloaws`
27
+ Then the output should contain:
28
+ """
29
+ ERROR:
30
+ """
31
+ And the exit status should be 1
data/lib/zerg.rb ADDED
@@ -0,0 +1,30 @@
1
+ #--
2
+
3
+ # Copyright 2014 by MTN Sattelite Communications
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to
7
+ # deal in the Software without restriction, including without limitation the
8
+ # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9
+ # sell copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20
+ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21
+ # IN THE SOFTWARE.
22
+ #++
23
+
24
+ require "zerg/hive"
25
+ require "zerg/runner"
26
+ require "zerg/driver_renderer"
27
+
28
+ module Zerg
29
+
30
+ end
data/lib/zerg/cli.rb ADDED
@@ -0,0 +1,85 @@
1
+ #--
2
+
3
+ # Copyright 2014 by MTN Sattelite Communications
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to
7
+ # deal in the Software without restriction, including without limitation the
8
+ # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9
+ # sell copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20
+ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21
+ # IN THE SOFTWARE.
22
+ #++
23
+
24
+ require 'thor'
25
+ require 'zerg'
26
+ require 'zerg/generators/hivegen'
27
+
28
+ module Zerg
29
+ class HiveCLI < Thor
30
+ class_option :force, :type => :boolean, :banner => "force overwrite of files"
31
+
32
+ # hack (https://github.com/erikhuda/thor/issues/261#issuecomment-16880836)
33
+ # to get around thor showing klass name snake case in subcommand help (instead of subcommand name)
34
+ package_name "hive"
35
+ def self.banner(command, namespace = nil, subcommand = false)
36
+ "#{basename} #{@package_name} #{command.usage}"
37
+ end
38
+
39
+ desc "verify", "verifies hive tasks without loading them"
40
+ def verify
41
+ puts Zerg::Hive.verify
42
+ end
43
+
44
+ desc "list", "lists hive tasks"
45
+ def list
46
+ puts Zerg::Hive.list
47
+ end
48
+
49
+ desc "import [FILE]", "import a .ke file into the hive folder"
50
+ def import(file)
51
+ puts Zerg::Hive.import(file, options[:force])
52
+ end
53
+
54
+ desc "remove [TASK]", "remove a task from hive"
55
+ def remove(file)
56
+ puts Zerg::Hive.remove(file, options[:force])
57
+ end
58
+ end
59
+
60
+ class CLI < Thor
61
+ class_option :force, :type => :boolean, :banner => "force overwrite of files"
62
+ class_option :debug, :type => :boolean, :banner => "add debug option to driver"
63
+
64
+ def self.exit_on_failure?
65
+ true
66
+ end
67
+
68
+ desc "init", "initializes new hive"
69
+ def init
70
+ puts Zerg::Generators::HiveGen.start
71
+ end
72
+
73
+ desc "rush [TASK]", "runs a task from hive"
74
+ def rush(task)
75
+ puts Zerg::Runner.rush(task, options[:debug])
76
+ end
77
+
78
+ desc "clean [TASK]", "cleans a task"
79
+ def clean(task)
80
+ puts Zerg::Runner.clean(task, options[:debug])
81
+ end
82
+
83
+ register(HiveCLI, 'hive', 'hive [COMMAND]', 'Manage hive - a collection of task descriptions.')
84
+ end
85
+ end
@@ -0,0 +1,190 @@
1
+ #--
2
+
3
+ # Copyright 2014 by MTN Sattelite Communications
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to
7
+ # deal in the Software without restriction, including without limitation the
8
+ # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9
+ # sell copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20
+ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21
+ # IN THE SOFTWARE.
22
+ #++
23
+
24
+ require 'awesome_print'
25
+ require 'fileutils'
26
+ require 'erb'
27
+ require 'ostruct'
28
+ require 'securerandom'
29
+
30
+ module Zerg
31
+ class DriverRenderer
32
+ class Erbalize < OpenStruct
33
+ def self.erbalize_hash(template, sources)
34
+ Erbalize.new(sources).render(template)
35
+ end
36
+
37
+ def render(template)
38
+ ERB.new(template, nil, '-').result(binding)
39
+ end
40
+ end
41
+
42
+ # generate a virtualbox - compatible MAC address
43
+ def generateMACAddress()
44
+ firstChar = (0..255).map(&:chr).select{|x| x =~ /[0-9A-Fa-f]/}.sample(1).join
45
+ secondChar = (0..255).map(&:chr).select{|x| x =~ /[02468ACEace]/}.sample(1).join
46
+ restOfChars = (0..255).map(&:chr).select{|x| x =~ /[0-9A-Fa-f]/}.sample(10).join
47
+ return "#{firstChar}#{secondChar}#{restOfChars}"
48
+ end
49
+
50
+ def initialize(vm, name, instances, synced_folders, tasks )
51
+ @vm = vm
52
+ @name = name
53
+ @instances = instances
54
+ @tasks = tasks
55
+ @synced_folders = synced_folders
56
+ end
57
+
58
+ def render
59
+ puts ("Rendering driver templates...")
60
+
61
+ # TODO: generalize this processing better
62
+ abort("ERROR: Driver type '#{@vm["driver"]["drivertype"]} is not supported.") unless (@vm["driver"]["drivertype"] == "vagrant")
63
+
64
+ # load the template files
65
+ main_template = File.open(File.join("#{File.dirname(__FILE__)}", "..", "..", "data", "driver", "#{@vm["driver"]["drivertype"]}", "main.template"), 'r').read
66
+
67
+ # load the provider top level template
68
+ provider_parent_template = File.open(File.join("#{File.dirname(__FILE__)}", "..", "..", "data", "driver", "#{@vm["driver"]["drivertype"]}", "provider.template"), 'r').read
69
+
70
+ # load the machine details template
71
+ machine_template = File.open(File.join("#{File.dirname(__FILE__)}", "..", "..", "data", "driver", "#{@vm["driver"]["drivertype"]}", "machine.template"), 'r').read
72
+
73
+ # load the bridge details template
74
+ bridge_template = File.open(File.join("#{File.dirname(__FILE__)}", "..", "..", "data", "driver", "#{@vm["driver"]["drivertype"]}", "bridging.template"), 'r').read
75
+
76
+ # load the host only network details template
77
+ hostonly_template = File.open(File.join("#{File.dirname(__FILE__)}", "..", "..", "data", "driver", "#{@vm["driver"]["drivertype"]}", "hostonly.template"), 'r').read
78
+
79
+ # render templates....
80
+ # render provider details to string
81
+ #
82
+ # render provider details into a string
83
+ provider_details_array = @vm["driver"]["provider_options"]
84
+ provider_details = ""
85
+ for index in 0..provider_details_array.length - 1
86
+ provider_details += "\t\t" + provider_details_array[index] + "\n"
87
+ end
88
+
89
+ # render provider parent
90
+ sources = {
91
+ :provider => @vm["driver"]["providertype"],
92
+ :provider_specifics => provider_details
93
+ }
94
+ provider_parent_string = Erbalize.erbalize_hash(provider_parent_template, sources)
95
+
96
+ # render machine template
97
+ all_macs = Array.new
98
+ all_machines = ""
99
+ for index in 0..@instances - 1
100
+
101
+ # last ip octet offset for host only networking
102
+ ip_octet_offset = index
103
+
104
+ # inject randomized node_name into chef_client tasks
105
+ @tasks.each { |task|
106
+ if task["type"] == "chef_client"
107
+ task["node_name"] = "zergling_#{index}_#{SecureRandom.hex(20)}"
108
+ end
109
+ }
110
+
111
+ # tasks array rendered to ruby string. double encoding to escape quotes and allow for variable expansion
112
+ tasks_array = @tasks.to_json.to_json
113
+
114
+ # do we need the bridging template as well?
115
+ bridge_section = nil
116
+ if @vm.has_key?("bridge_description")
117
+ # mac address to use?
118
+ new_mac = ""
119
+ begin
120
+ new_mac = generateMACAddress()
121
+ end while all_macs.include? new_mac
122
+
123
+ sources = {
124
+ :machine_mac => new_mac,
125
+ :bridged_eth_description => @vm["bridge_description"]
126
+ }
127
+ bridge_section = Erbalize.erbalize_hash(bridge_template, sources)
128
+ end
129
+
130
+ # do we need the host only template as well?
131
+ hostonly_section = nil
132
+ if @vm["private_network"] == true
133
+ sources = {
134
+ :machine_name => "zergling_#{index}",
135
+ :last_octet => ip_octet_offset + 4, # TODO: this is probably specific to virtualbox networking
136
+ }
137
+ hostonly_section = Erbalize.erbalize_hash(hostonly_template, sources)
138
+ end
139
+
140
+ # blah
141
+ folder_definitions = nil
142
+ if @synced_folders != nil
143
+ folder_definitions = ""
144
+ @synced_folders.each { |folder|
145
+ other_options = ""
146
+ if folder.has_key?("options")
147
+ folder["options"].each { |option|
148
+ option.each do |key, value|
149
+ if value.is_a?(String)
150
+ other_options += ", :#{key} => \"#{value}\""
151
+ else
152
+ other_options += ", :#{key} => #{value}"
153
+ end
154
+ end
155
+ }
156
+ end
157
+
158
+ folder_definition = "zergling_#{index}.vm.synced_folder \"#{folder['host_path']}\", \"#{folder['guest_path']}\""
159
+ folder_definition = "#{folder_definition}#{other_options}" unless other_options.empty?()
160
+ folder_definitions += "\t\t#{folder_definition}\n"
161
+ }
162
+ end
163
+
164
+ sources = {
165
+ :machine_name => "zergling_#{index}",
166
+ :bridge_specifics => bridge_section,
167
+ :hostonly_specifics => hostonly_section,
168
+ :tasks_array => tasks_array,
169
+ :sync_folders_array => folder_definitions
170
+ }.delete_if { |k, v| v.nil? }
171
+
172
+ machine_section = Erbalize.erbalize_hash(machine_template, sources)
173
+ all_machines += "\n#{machine_section}"
174
+ end
175
+
176
+ sources = {
177
+ :provider_section => provider_parent_string,
178
+ :basebox_path => @vm["basebox"],
179
+ :box_name => "zergling_#{@name}_#{@vm["driver"]["providertype"]}",
180
+ :vm_defines => all_machines
181
+ }
182
+ full_template = Erbalize.erbalize_hash(main_template, sources)
183
+
184
+ # write the file
185
+ puts ("Writing #{File.join("#{Dir.pwd}", ".hive", "driver", @vm["driver"]["drivertype"], @name, "Vagrantfile")}...")
186
+ FileUtils.mkdir_p(File.join("#{Dir.pwd}", ".hive", "driver", @vm["driver"]["drivertype"], @name))
187
+ File.open(File.join("#{Dir.pwd}", ".hive", "driver", @vm["driver"]["drivertype"], @name, "Vagrantfile"), 'w') { |file| file.write(full_template) }
188
+ end
189
+ end
190
+ end