mccloud 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.
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