mccloud 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. data/.gitignore +5 -0
  2. data/.rvmrc +4 -0
  3. data/Gemfile +4 -0
  4. data/Gemfile.lock +74 -0
  5. data/README.md +123 -0
  6. data/Rakefile +5 -0
  7. data/bin/mccloud +116 -0
  8. data/lib/mccloud.rb +2 -0
  9. data/lib/mccloud/command/boot.rb +12 -0
  10. data/lib/mccloud/command/bootstrap.rb +31 -0
  11. data/lib/mccloud/command/command.rb +21 -0
  12. data/lib/mccloud/command/destroy.rb +19 -0
  13. data/lib/mccloud/command/halt.rb +19 -0
  14. data/lib/mccloud/command/init.rb +7 -0
  15. data/lib/mccloud/command/multi.rb +53 -0
  16. data/lib/mccloud/command/provision.rb +28 -0
  17. data/lib/mccloud/command/reload.rb +11 -0
  18. data/lib/mccloud/command/server.rb +30 -0
  19. data/lib/mccloud/command/ssh.rb +46 -0
  20. data/lib/mccloud/command/status.rb +31 -0
  21. data/lib/mccloud/command/suspend.rb +15 -0
  22. data/lib/mccloud/command/up.rb +65 -0
  23. data/lib/mccloud/config.rb +47 -0
  24. data/lib/mccloud/configurator/lb.rb +26 -0
  25. data/lib/mccloud/configurator/mccloud.rb +13 -0
  26. data/lib/mccloud/configurator/vm.rb +37 -0
  27. data/lib/mccloud/generators.rb +28 -0
  28. data/lib/mccloud/provisioner/chef_solo.rb +149 -0
  29. data/lib/mccloud/provisioner/puppet.rb +39 -0
  30. data/lib/mccloud/provisioner/vagrant/base.rb +63 -0
  31. data/lib/mccloud/provisioner/vagrant/chef.rb +130 -0
  32. data/lib/mccloud/provisioner/vagrant/chef_server.rb +103 -0
  33. data/lib/mccloud/provisioner/vagrant/chef_solo.rb +142 -0
  34. data/lib/mccloud/provisioner/vagrant/puppet.rb +137 -0
  35. data/lib/mccloud/provisioner/vagrant/puppet_server.rb +55 -0
  36. data/lib/mccloud/provisioner/vagrant/shell.rb +52 -0
  37. data/lib/mccloud/session.rb +199 -0
  38. data/lib/mccloud/templates/Mccloudfilet +44 -0
  39. data/lib/mccloud/type/forwarding.rb +11 -0
  40. data/lib/mccloud/type/lb.rb +34 -0
  41. data/lib/mccloud/type/vm.rb +46 -0
  42. data/lib/mccloud/util/iterator.rb +21 -0
  43. data/lib/mccloud/util/platform.rb +29 -0
  44. data/lib/mccloud/util/rsync.rb +21 -0
  45. data/lib/mccloud/util/ssh.rb +167 -0
  46. data/lib/mccloud/version.rb +3 -0
  47. data/mccloud.gemspec +37 -0
  48. data/ruby-bootstrap.sh +11 -0
  49. data/ruby-bootstrap2.sh +39 -0
  50. metadata +297 -0
@@ -0,0 +1,142 @@
1
+ module Vagrant
2
+ module Provisioners
3
+ # This class implements provisioning via chef-solo.
4
+ class ChefSolo < Chef
5
+ register :chef_solo
6
+
7
+ class Config < Chef::Config
8
+ attr_accessor :cookbooks_path
9
+ attr_accessor :roles_path
10
+ attr_accessor :recipe_url
11
+
12
+ def initialize
13
+ super
14
+
15
+ @cookbooks_path = ["cookbooks", [:vm, "cookbooks"]]
16
+ @roles_path = []
17
+ end
18
+
19
+ def validate(errors)
20
+ super
21
+
22
+ errors.add(I18n.t("vagrant.config.chef.cookbooks_path_empty")) if !cookbooks_path || [cookbooks_path].flatten.empty?
23
+ errors.add(I18n.t("vagrant.config.chef.run_list_empty")) if !json[:run_list] || run_list.empty?
24
+ end
25
+ end
26
+
27
+ def prepare
28
+ share_cookbook_folders
29
+ share_role_folders
30
+ end
31
+
32
+ def provision!
33
+ verify_binary("chef-solo")
34
+ chown_provisioning_folder
35
+ setup_json
36
+ setup_solo_config
37
+ run_chef_solo
38
+ end
39
+
40
+ def share_cookbook_folders
41
+ host_cookbook_paths.each_with_index do |cookbook, i|
42
+ env.config.vm.share_folder("v-csc-#{i}", cookbook_path(i), cookbook)
43
+ end
44
+ end
45
+
46
+ def share_role_folders
47
+ host_role_paths.each_with_index do |role, i|
48
+ env.config.vm.share_folder("v-csr-#{i}", role_path(i), role)
49
+ end
50
+ end
51
+
52
+ def setup_solo_config
53
+ setup_config("chef_solo_solo", "solo.rb", {
54
+ :node_name => config.node_name,
55
+ :provisioning_path => config.provisioning_path,
56
+ :cookbooks_path => cookbooks_path,
57
+ :recipe_url => config.recipe_url,
58
+ :roles_path => roles_path,
59
+ })
60
+ end
61
+
62
+ def run_chef_solo
63
+ commands = ["cd #{config.provisioning_path}", "chef-solo -c solo.rb -j dna.json"]
64
+
65
+ env.ui.info I18n.t("vagrant.provisioners.chef.running_solo")
66
+ vm.ssh.execute do |ssh|
67
+ ssh.sudo!(commands) do |channel, type, data|
68
+ if type == :exit_status
69
+ ssh.check_exit_status(data, commands)
70
+ else
71
+ env.ui.info("#{data}: #{type}")
72
+ end
73
+ end
74
+ end
75
+ end
76
+
77
+ def host_folder_paths(paths)
78
+ # Convert single cookbook paths such as "cookbooks" or [:vm, "cookbooks"]
79
+ # into a proper array representation.
80
+ paths = [paths] if paths.is_a?(String) || paths.first.is_a?(Symbol)
81
+
82
+ paths.inject([]) do |acc, path|
83
+ path = [:host, path] if !path.is_a?(Array)
84
+ type, path = path
85
+
86
+ acc << File.expand_path(path, env.root_path) if type == :host
87
+ acc
88
+ end
89
+ end
90
+
91
+ def folder_path(*args)
92
+ File.join(config.provisioning_path, args.join("-"))
93
+ end
94
+
95
+ def folders_path(folders, folder)
96
+ # Convert single cookbook paths such as "cookbooks" or [:vm, "cookbooks"]
97
+ # into a proper array representation.
98
+ folders = [folders] if folders.is_a?(String) || folders.first.is_a?(Symbol)
99
+
100
+ # Convert each path to the proper absolute path depending on if the path
101
+ # is a host path or a VM path
102
+ result = []
103
+ folders.each_with_index do |path, i|
104
+ path = [:host, path] if !path.is_a?(Array)
105
+ type, path = path
106
+
107
+ result << folder_path(folder, i) if type == :host
108
+ result << folder_path(path) if type == :vm
109
+ end
110
+
111
+ # We're lucky that ruby's string and array syntax for strings is the
112
+ # same as JSON, so we can just convert to JSON here and use that
113
+ result = result[0].to_s if result.length == 1
114
+ result
115
+ end
116
+
117
+ def host_cookbook_paths
118
+ host_folder_paths(config.cookbooks_path)
119
+ end
120
+
121
+ def host_role_paths
122
+ host_folder_paths(config.roles_path)
123
+ end
124
+
125
+ def cookbook_path(i)
126
+ folder_path("cookbooks", i)
127
+ end
128
+
129
+ def role_path(i)
130
+ folder_path("roles", i)
131
+ end
132
+
133
+ def cookbooks_path
134
+ folders_path(config.cookbooks_path, "cookbooks").to_json
135
+ end
136
+
137
+ def roles_path
138
+ folders_path(config.roles_path, "roles").to_json
139
+ end
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,137 @@
1
+ module Vagrant
2
+ module Provisioners
3
+ class PuppetError < Vagrant::Errors::VagrantError
4
+ error_namespace("vagrant.provisioners.puppet")
5
+ end
6
+
7
+ class Puppet < Base
8
+ register :puppet
9
+
10
+ class Config < Vagrant::Config::Base
11
+ attr_accessor :manifest_file
12
+ attr_accessor :manifests_path
13
+ attr_accessor :module_path
14
+ attr_accessor :pp_path
15
+ attr_accessor :options
16
+
17
+ def initialize
18
+ @manifest_file = nil
19
+ @manifests_path = "manifests"
20
+ @module_path = nil
21
+ @pp_path = "/tmp/vagrant-puppet"
22
+ @options = []
23
+ end
24
+
25
+ # Returns the manifests path expanded relative to the root path of the
26
+ # environment.
27
+ def expanded_manifests_path
28
+ Pathname.new(manifests_path).expand_path(env.root_path)
29
+ end
30
+
31
+ # Returns the manifest file if set otherwise returns the box name pp file
32
+ # which may or may not exist.
33
+ def computed_manifest_file
34
+ manifest_file || "#{top.vm.box}.pp"
35
+ end
36
+
37
+ # Returns the module paths as an array of paths expanded relative to the
38
+ # root path.
39
+ def expanded_module_paths
40
+ return [] if !module_path
41
+
42
+ # Get all the paths and expand them relative to the root path, returning
43
+ # the array of expanded paths
44
+ paths = module_path
45
+ paths = [paths] if !paths.is_a?(Array)
46
+ paths.map do |path|
47
+ Pathname.new(path).expand_path(env.root_path)
48
+ end
49
+ end
50
+
51
+ def validate(errors)
52
+ super
53
+
54
+ # Manifests path/file validation
55
+ if !expanded_manifests_path.directory?
56
+ errors.add(I18n.t("vagrant.provisioners.puppet.manifests_path_missing", :path => expanded_manifests_path))
57
+ else
58
+ if !expanded_manifests_path.join(computed_manifest_file).file?
59
+ errors.add(I18n.t("vagrant.provisioners.puppet.manifest_missing", :manifest => computed_manifest_file))
60
+ end
61
+ end
62
+
63
+ # Module paths validation
64
+ expanded_module_paths.each do |path|
65
+ if !path.directory?
66
+ errors.add(I18n.t("vagrant.provisioners.puppet.module_path_missing", :path => path))
67
+ end
68
+ end
69
+ end
70
+ end
71
+
72
+ def prepare
73
+ set_module_paths
74
+ share_manifests
75
+ share_module_paths
76
+ end
77
+
78
+ def provision!
79
+ verify_binary("puppet")
80
+ run_puppet_client
81
+ end
82
+
83
+ def share_manifests
84
+ env.config.vm.share_folder("manifests", manifests_guest_path, config.expanded_manifests_path)
85
+ end
86
+
87
+ def share_module_paths
88
+ count = 0
89
+ @module_paths.each do |from, to|
90
+ # Sorry for the cryptic key here, but VirtualBox has a strange limit on
91
+ # maximum size for it and its something small (around 10)
92
+ env.config.vm.share_folder("v-pp-m#{count}", to, from)
93
+ count += 1
94
+ end
95
+ end
96
+
97
+ def set_module_paths
98
+ @module_paths = {}
99
+ config.expanded_module_paths.each_with_index do |path, i|
100
+ @module_paths[path] = File.join(config.pp_path, "modules-#{i}")
101
+ end
102
+ end
103
+
104
+ def manifests_guest_path
105
+ File.join(config.pp_path, "manifests")
106
+ end
107
+
108
+ def verify_binary(binary)
109
+ vm.ssh.execute do |ssh|
110
+ ssh.sudo!("which #{binary}", :error_class => PuppetError, :_key => :puppet_not_detected, :binary => binary)
111
+ end
112
+ end
113
+
114
+ def run_puppet_client
115
+ options = [config.options].flatten
116
+ options << "--modulepath '#{@module_paths.values.join(':')}'" if !@module_paths.empty?
117
+ options << config.computed_manifest_file
118
+ options = options.join(" ")
119
+
120
+ commands = ["cd #{manifests_guest_path}",
121
+ "puppet #{options}"]
122
+
123
+ env.ui.info I18n.t("vagrant.provisioners.puppet.running_puppet", :manifest => config.computed_manifest_file)
124
+
125
+ vm.ssh.execute do |ssh|
126
+ ssh.sudo! commands do |ch, type, data|
127
+ if type == :exit_status
128
+ ssh.check_exit_status(data, commands)
129
+ else
130
+ env.ui.info(data)
131
+ end
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,55 @@
1
+ module Vagrant
2
+ module Provisioners
3
+ class PuppetServerError < Vagrant::Errors::VagrantError
4
+ error_namespace("vagrant.provisioners.puppet_server")
5
+ end
6
+
7
+ class PuppetServer < Base
8
+ register :puppet_server
9
+
10
+ class Config < Vagrant::Config::Base
11
+ attr_accessor :puppet_server
12
+ attr_accessor :puppet_node
13
+ attr_accessor :options
14
+
15
+ def initialize
16
+ @puppet_server = "puppet"
17
+ @puppet_node = "puppet_node"
18
+ @options = []
19
+ end
20
+ end
21
+
22
+ def provision!
23
+ verify_binary("puppetd")
24
+ run_puppetd_client
25
+ end
26
+
27
+ def verify_binary(binary)
28
+ vm.ssh.execute do |ssh|
29
+ ssh.sudo!("which #{binary}", :error_class => PuppetServerError, :_key => :puppetd_not_detected, :binary => binary)
30
+ end
31
+ end
32
+
33
+ def run_puppetd_client
34
+ options = config.options
35
+ options = options.join(" ") if options.is_a?(Array)
36
+ if config.puppet_node
37
+ cn = config.puppet_node
38
+ else
39
+ cn = env.config.vm.box
40
+ end
41
+
42
+ commands = "puppetd #{options} --server #{config.puppet_server} --certname #{cn}"
43
+
44
+ env.ui.info I18n.t("vagrant.provisioners.puppet_server.running_puppetd")
45
+
46
+ vm.ssh.execute do |ssh|
47
+ ssh.sudo!(commands) do |channel, type, data|
48
+ ssh.check_exit_status(data, commands) if type == :exit_status
49
+ env.ui.info(data) if type != :exit_status
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,52 @@
1
+ module Vagrant
2
+ module Provisioners
3
+ class Shell < Base
4
+ register :shell
5
+
6
+ class Config < Vagrant::Config::Base
7
+ attr_accessor :path
8
+ attr_accessor :upload_path
9
+
10
+ def initialize
11
+ @upload_path = "/tmp/vagrant-shell"
12
+ end
13
+
14
+ def expanded_path
15
+ Pathname.new(path).expand_path(env.root_path) if path
16
+ end
17
+
18
+ def validate(errors)
19
+ super
20
+
21
+ if !path
22
+ errors.add(I18n.t("vagrant.provisioners.shell.path_not_set"))
23
+ elsif !expanded_path.file?
24
+ errors.add(I18n.t("vagrant.provisioners.shell.path_invalid", :path => expanded_path))
25
+ end
26
+
27
+ if !upload_path
28
+ errors.add(I18n.t("vagrant.provisioners.shell.upload_path_not_set"))
29
+ end
30
+ end
31
+ end
32
+
33
+ def provision!
34
+ commands = ["chmod +x #{config.upload_path}", config.upload_path]
35
+
36
+ # Upload the script to the VM
37
+ vm.ssh.upload!(config.expanded_path.to_s, config.upload_path)
38
+
39
+ # Execute it with sudo
40
+ vm.ssh.execute do |ssh|
41
+ ssh.sudo!(commands) do |ch, type, data|
42
+ if type == :exit_status
43
+ ssh.check_exit_status(data, commands)
44
+ else
45
+ env.ui.info(data)
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,199 @@
1
+ require 'json'
2
+ require 'logger'
3
+
4
+
5
+ require 'fog'
6
+ require 'highline'
7
+ require 'highline/import'
8
+
9
+ require 'mccloud/config'
10
+
11
+ require 'mccloud/command/status'
12
+ require 'mccloud/command/up'
13
+ require 'mccloud/command/halt'
14
+ require 'mccloud/command/ssh'
15
+ require 'mccloud/command/boot'
16
+ require 'mccloud/command/bootstrap'
17
+ require 'mccloud/command/reload'
18
+ require 'mccloud/command/multi'
19
+ require 'mccloud/command/init'
20
+ require 'mccloud/command/suspend'
21
+ require 'mccloud/command/destroy'
22
+ require 'mccloud/command/provision'
23
+ require 'mccloud/command/server'
24
+
25
+ module Mccloud
26
+
27
+ # We need some global thing for the config file to find our session
28
+ def self.session=(value)
29
+ @session=value
30
+ end
31
+ def self.session
32
+ return @session
33
+ end
34
+
35
+ class Session
36
+ attr_accessor :config
37
+ attr_accessor :logger
38
+ attr_accessor :all_servers
39
+
40
+ include Mccloud::Command
41
+
42
+ def initialize(options=nil)
43
+ @logger = Logger.new(STDOUT)
44
+ @logger.level = Logger::DEBUG
45
+
46
+ #http://www.ruby-doc.org/stdlib/libdoc/logger/rdoc/classes/Logger.html
47
+ @logger.datetime_format = "%Y-%m-%d %H:%M:%S"
48
+
49
+ #logger.formatter = proc { |severity, datetime, progname, msg|
50
+ # "#{datetime} - #{severity}: #{msg}\n"
51
+ # }
52
+ @session=self
53
+ Mccloud.session=self
54
+ end
55
+
56
+ def load_config(options=nil)
57
+ @logger.debug "Loading mccloud config"
58
+ #if File.exist?(path)
59
+ begin
60
+ Kernel.load File.join(Dir.pwd,"Mccloudfile")
61
+ rescue LoadError => e
62
+ @logger.error "Error loading configfile - Sorry"
63
+ @logger.error e.message
64
+ @logger.error e.backtrace.inspect
65
+ exit -1
66
+ end
67
+
68
+ @all_servers=Hash.new
69
+ if File.exists?(".mccloud")
70
+
71
+ @logger.debug ".mccloud exists"
72
+ dotmccloud=File.new(".mccloud")
73
+
74
+ @logger.debug "reading .mccloud json file"
75
+ json=dotmccloud.readlines.to_s
76
+
77
+ begin
78
+ @logger.debug "parsing .mccloud json file"
79
+ @all_servers=JSON.parse(json)
80
+ rescue Error => e
81
+ @logger.error "Error parsing json file - Sorry"
82
+ @logger.error e.message
83
+ @logger.error e.backtrace.inspect
84
+ exit -1
85
+ end
86
+
87
+ end
88
+
89
+ #Loading providers
90
+ Mccloud.session.config.vms.each do |name,vm|
91
+ if @session.config.providers[vm.provider].nil?
92
+
93
+ @logger.debug "adding provider #{vm.provider}"
94
+ begin
95
+ @session.config.providers[vm.provider]=Fog::Compute.new(:provider => vm.provider)
96
+ rescue ArgumentError => e
97
+ # Missing required arguments:
98
+ required_string=e.message
99
+ required_string["Missing required arguments: "]=""
100
+ required_options=required_string.split(", ")
101
+ puts "Please provide credentials for provider [#{vm.provider}]:"
102
+ answer=Hash.new
103
+ for fog_option in required_options do
104
+ answer["#{fog_option}".to_sym]=ask("- #{fog_option}: ")
105
+ #{ |q| q.validate = /\A\d{5}(?:-?\d{4})?\Z/ }
106
+ end
107
+ puts "\nThe following snippet will be written to #{File.join(ENV['HOME'],".fog")}"
108
+
109
+ snippet=":default:\n"
110
+ for fog_option in required_options do
111
+ snippet=snippet+" :#{fog_option}: #{answer[fog_option.to_sym]}\n"
112
+ end
113
+
114
+ puts "======== snippit start ====="
115
+ puts "#{snippet}"
116
+ puts "======== snippit end ======="
117
+ confirmed=agree("Do you wan to save this?: ")
118
+
119
+ if (confirmed)
120
+ fogfile=File.new("#{File.join(ENV['HOME'],".fog")}","w")
121
+ fogfile.puts "#{snippet}"
122
+ fogfile.close
123
+ else
124
+ puts "Ok, we won't write it, but we continue with your credentials in memory"
125
+ exit -1
126
+ end
127
+ begin
128
+ answer[:provider]= vm.provider
129
+ @session.config.providers[vm.provider]=Fog::Compute.new(answer)
130
+ rescue
131
+ puts "We tried to create the provider but failed again, sorry we give up"
132
+ exit -1
133
+ end
134
+ end
135
+ end
136
+ end
137
+
138
+ invalid_cache=false
139
+ @session.config.vms.each do |name,vm|
140
+ prefix=@session.config.mccloud.prefix
141
+ id=@all_servers["#{name.to_s}"]
142
+
143
+ #Check if not destroyed or something else
144
+ instance=vm.instance
145
+ if instance.nil?
146
+ @logger.error "Cache is invalid"
147
+ invalid_cache=true
148
+ else
149
+ if instance.state == "shutting-down" || instance.state == "terminated"
150
+ @logger.info "parsing .mccloud json"
151
+ @logger.info "rebuilding cache"
152
+ invalid_cache=true
153
+ end
154
+ end
155
+ end
156
+
157
+ #
158
+ if (invalid_cache)
159
+ #Resetting the list
160
+ @all_servers=Hash.new
161
+
162
+ servers_by_provider=Hash.new
163
+
164
+ # Find all providers
165
+ @session.config.providers.each do |name,provider|
166
+ server_list=Hash.new
167
+ provider.servers.each do |server|
168
+
169
+ if !(server.state == "terminated")
170
+ server_list[server.tags["Name"]]=server.id
171
+ end
172
+ end
173
+ servers_by_provider[name]=server_list
174
+ end
175
+ prefix=@session.config.mccloud.prefix
176
+
177
+ @session.config.vms.each do |name,vm|
178
+ id=servers_by_provider[vm.provider]["#{prefix} - #{name.to_s}"]
179
+
180
+
181
+ if !id.nil?
182
+ @all_servers[name]=id
183
+ #@session.config.vms[name].instance=@session.config.providers[vm.provider].servers.get(id)
184
+ end
185
+ end
186
+
187
+ dotmccloud=File.new(".mccloud","w")
188
+ dotmccloud.puts(@all_servers.to_json)
189
+ dotmccloud.close
190
+
191
+
192
+ end
193
+ end
194
+
195
+
196
+
197
+
198
+ end
199
+ end