small_wonder 0.1.6 → 0.1.7

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -23,11 +23,12 @@ Apache License Version 2.0
23
23
  chef_repo_path "/path/to/chef-repo" # the path to your chef-repo
24
24
  ssh_user "user" # the ssh user you want Small Wonder and Salticid to use
25
25
  application_deployment_attribute "deployed_applications" # the attribute Small Wonder will save data back to chef using
26
- config_template_working_directory "/tmp/small_wonder" # the local directory temporary template work will be done in
27
- remote_working_dir "/tmp/small_wonder_#{Time.now.to_i}" # the remote directory temporary template work will be done in
28
26
  application_deployments_dir "/path/to/chef-repo/application_deployments" # path to your role files
29
27
  application_templates_dir "/path/to/chef-repo/application_templates" # path to your template files
30
28
  databag "apps" # the databag that contains application configuration data items
29
+ default_metadata Hash["timestamp" => Time.now.to_i, "deploy_by" => ENV['USER']] # metadata saved to chef with each deploy
30
+ pre_deploy_hooks ["/path/to/a/hook/example.rb"]
31
+ post_deploy_hooks ["/path/to/a/hook/example.rb"]
31
32
 
32
33
  In addition to a Small Wonder config, you need a working Knife configuration file.
33
34
 
data/lib/small_wonder.rb CHANGED
@@ -11,6 +11,7 @@ require 'chef'
11
11
  require 'highline/import'
12
12
  require 'erb'
13
13
  require 'net/scp'
14
+ require 'tmpdir'
14
15
 
15
16
  __DIR__ = File.dirname(__FILE__)
16
17
 
@@ -77,16 +78,6 @@ module SmallWonder
77
78
 
78
79
  def main()
79
80
 
80
- unless SmallWonder::Utils.sane_working_dir?(SmallWonder::Config.remote_working_dir)
81
- SmallWonder::Log.error("Your remote working dir looks strange (#{SmallWonder::Config.remote_working_dir})")
82
- exit(1)
83
- end
84
-
85
- unless SmallWonder::Utils.sane_working_dir?(SmallWonder::Config.config_template_working_directory)
86
- SmallWonder::Log.error("Your local working dir looks strange (#{SmallWonder::Config.config_template_working_directory})")
87
- exit(1)
88
- end
89
-
90
81
  # inintialize chef/knife config
91
82
  Chef::Config[:node_name] = SmallWonder::Config.node_name
92
83
  Chef::Config[:client_key] = SmallWonder::Config.client_key
@@ -42,6 +42,11 @@ module SmallWonder
42
42
 
43
43
  # save the data back to the chef node
44
44
  update_application_data(node_name, application_name, "status", "initialized")
45
+
46
+ # save metadata back to chef
47
+ if opts[:metadata]
48
+ update_application_data(node_name, application_name, "data", opts[:metadata])
49
+ end
45
50
  end
46
51
 
47
52
  def version=(version)
@@ -56,16 +61,6 @@ module SmallWonder
56
61
 
57
62
  private
58
63
 
59
- def get_existing_version(node, application)
60
- version = get_chef_data_value(node, application, "version")
61
-
62
- unless version
63
- version = "0"
64
- end
65
-
66
- version
67
- end
68
-
69
64
  def set_version(node, application, version)
70
65
  update_application_data(node, application, "version", version)
71
66
  end
@@ -51,6 +51,24 @@ module SmallWonder
51
51
  :default => :info,
52
52
  :proc => Proc.new { |l| l.to_sym }
53
53
 
54
+ option :config_template_working_directory,
55
+ :short => "-D",
56
+ :long => "--working-dir",
57
+ :description => "local config template working directory",
58
+ :default => Dir.mktmpdir
59
+
60
+ option :remote_working_dir,
61
+ :short => "-R",
62
+ :long => "--remote-working-dir",
63
+ :description => "remote config template working directory",
64
+ :default => "/tmp/small_wonder_#{Time.now.to_i}"
65
+
66
+ option :dynamic_metadata,
67
+ :short => "-M JSON",
68
+ :long => "--metadata JSON",
69
+ :description => "Metadata JSON",
70
+ :default => nil
71
+
54
72
  help = <<-EOH
55
73
 
56
74
  Examples:
@@ -2,6 +2,13 @@ module SmallWonder
2
2
  class Configuratorator
3
3
 
4
4
  def self.generate_and_upload_files(application, path, opts = {})
5
+ file_list = generate_files(application, path, opts)
6
+ upload_files(application)
7
+ apply_files(application, path, opts)
8
+ file_list
9
+ end
10
+
11
+ def self.generate_files(application, path, opts = {})
5
12
  config_template_dir = "#{SmallWonder::Config.application_templates_dir}/#{application.application_name}"
6
13
 
7
14
  templates = Dir["#{config_template_dir}/**/*.erb"]
@@ -9,11 +16,16 @@ module SmallWonder
9
16
  file_list = []
10
17
 
11
18
  templates.each do |file|
12
- filename = File.basename(file, '.*')
13
- filename.gsub!("VERSION", application.version)
19
+ begin
20
+ filename = File.basename(file, '.*')
21
+ filename.gsub!("VERSION", application.version)
14
22
 
15
- reldir = File.dirname(file).gsub("#{config_template_dir}", ".")
16
- reldir.gsub!("VERSION", application.version)
23
+ reldir = File.dirname(file).gsub("#{config_template_dir}", ".")
24
+ reldir.gsub!("VERSION", application.version)
25
+ rescue Exception => e
26
+ SmallWonder::Log.fatal("Something went badly attempting to replace VERSION with the version number, likely missing version data.\nerror: #{e}")
27
+ exit(1)
28
+ end
17
29
 
18
30
  file_list << "#{reldir}/#{filename}"
19
31
 
@@ -21,18 +33,32 @@ module SmallWonder
21
33
 
22
34
  generated_file = generate_file(file, application, config_template_dir, opts)
23
35
 
24
- file_dir = "#{SmallWonder::Config.config_template_working_directory}/#{application.application_name}/#{reldir}"
36
+ file_dir = "#{SmallWonder::Config.config_template_working_directory}/#{application.node_name}/#{application.application_name}/#{reldir}"
25
37
 
26
38
  FileUtils.mkdir_p(file_dir)
27
39
 
28
40
  SmallWonder::Utils.write_file(generated_file, "#{file_dir}/#{filename}")
29
41
  end
30
42
 
31
- upload_files(application.node_name, application.application_name)
43
+ file_list
44
+ end
45
+
46
+ def self.upload_files(application)
47
+ Net::SSH.start(application.node_name, SmallWonder::Config.ssh_user) do |ssh|
48
+ ssh.exec!("mkdir -p #{SmallWonder::Config.remote_working_dir}")
49
+ end
50
+
51
+ Net::SCP.start(application.node_name, SmallWonder::Config.ssh_user) do |scp|
52
+ scp.upload!("#{SmallWonder::Config.config_template_working_directory}/#{application.node_name}/#{application.application_name}", SmallWonder::Config.remote_working_dir, {:recursive => true})
53
+ end
54
+ end
55
+
56
+ def self.apply_files(application, path, opts = {})
32
57
  copy_files_to_install_dir(application.node_name, application.application_name, path)
33
- cleanup_working_directories(application.node_name, application.application_name)
34
58
 
35
- file_list
59
+ if opts[:no_cleanup]
60
+ cleanup_working_directories(application.node_name, application.application_name)
61
+ end
36
62
  end
37
63
 
38
64
  private
@@ -60,16 +86,6 @@ module SmallWonder
60
86
  template.result(binding)
61
87
  end
62
88
 
63
- def self.upload_files(node_name, application)
64
- Net::SSH.start(node_name, SmallWonder::Config.ssh_user) do |ssh|
65
- ssh.exec!("mkdir -p #{SmallWonder::Config.remote_working_dir}")
66
- end
67
-
68
- Net::SCP.start(node_name, SmallWonder::Config.ssh_user) do |scp|
69
- scp.upload!("#{SmallWonder::Config.config_template_working_directory}/#{application}", SmallWonder::Config.remote_working_dir, {:recursive => true})
70
- end
71
- end
72
-
73
89
  def self.copy_files_to_install_dir(node_name, application, path)
74
90
  Net::SSH.start(node_name, SmallWonder::Config.ssh_user) do |ssh|
75
91
  ssh.exec!("echo \"#{@sudo_password}\n\" | sudo -S cp -Rf #{SmallWonder::Config.remote_working_dir}/#{application}/* /#{path}/")
@@ -77,7 +93,7 @@ module SmallWonder
77
93
  end
78
94
 
79
95
  def self.cleanup_working_directories(node_name, application)
80
- FileUtils.rm_rf("#{SmallWonder::Config.config_template_working_directory}/#{application}")
96
+ FileUtils.rm_rf("#{SmallWonder::Config.config_template_working_directory}/#{node_name}/#{application}")
81
97
 
82
98
  Net::SSH.start(node_name, SmallWonder::Config.ssh_user) do |ssh|
83
99
  ssh.exec!("rm -rf #{SmallWonder::Config.remote_working_dir}")
@@ -48,15 +48,25 @@ module SmallWonder
48
48
  SmallWonder::Log.info("Did not get a app version to deploy on the command line, assuming you will set it during the deploy.")
49
49
  end
50
50
 
51
+ metadata = build_metadata(SmallWonder::Config.default_metadata, SmallWonder::Config.dynamic_metadata)
52
+
53
+ execute_pre_deploy_hooks(action, application_name, metadata, nodes, SmallWonder::Config.version)
54
+
55
+ application_objects = []
56
+
51
57
  nodes.each do |node|
52
58
  if SmallWonder::Config.version
53
- application = SmallWonder::Application.new(node, application_name, {:version => SmallWonder::Config.version})
59
+ application = SmallWonder::Application.new(node, application_name, {:version => SmallWonder::Config.version, :metadata => metadata})
54
60
  else
55
- application = SmallWonder::Application.new(node, application_name)
61
+ application = SmallWonder::Application.new(node, application_name, {:metadata => metadata})
56
62
  end
57
63
 
58
64
  deploy_application(action, application, sudo_password)
65
+ application_objects << application
59
66
  end
67
+
68
+ execute_post_deploy_hooks(action, application_name, metadata, nodes, application_objects, SmallWonder::Config.version)
69
+
60
70
  end
61
71
  else
62
72
  SmallWonder::Log.info("No nodes found for your search.")
@@ -71,6 +81,80 @@ module SmallWonder
71
81
  end
72
82
  end
73
83
 
84
+ def self.build_metadata(default = nil, dynamic = nil)
85
+ metadata = Hash.new
86
+
87
+ if default
88
+ metadata.store("default", default)
89
+ end
90
+
91
+ if dynamic
92
+ metadata.store("dynamic", JSON.parse(dynamic))
93
+ end
94
+
95
+ metadata
96
+ end
97
+
98
+ def self.build_hook_data(action, application_name, metadata, nodes, application_objects = nil, version = nil)
99
+ if application_objects
100
+ objs = []
101
+
102
+ application_objects.each do |obj|
103
+ hash = {}
104
+
105
+ obj.instance_variables.each do |var|
106
+ hash.store(var.to_s.delete("@"), obj.instance_variable_get(var))
107
+ end
108
+
109
+ objs << hash
110
+ end
111
+ end
112
+
113
+ {
114
+ "action" => action,
115
+ "application_name" => application_name,
116
+ "metadata" => metadata,
117
+ "nodes" => nodes,
118
+ "version" => version,
119
+ "application" => objs
120
+ }
121
+ end
122
+
123
+ def self.execute_pre_deploy_hooks(action, application_name, metadata, nodes, version)
124
+ data = build_hook_data(action, application_name, metadata, nodes, version)
125
+ execute_hooks(:pre, data)
126
+ end
127
+
128
+ def self.execute_post_deploy_hooks(action, application_name, metadata, nodes, application_objects, version)
129
+ data = build_hook_data(action, application_name, metadata, nodes, application_objects, version)
130
+ execute_hooks(:post, data)
131
+ end
132
+
133
+ def self.execute_hooks(type, data)
134
+ data_json = data.to_json
135
+
136
+ case type
137
+ when :pre
138
+ hooks = SmallWonder::Config.pre_deploy_hooks
139
+ when :post
140
+ hooks = SmallWonder::Config.post_deploy_hooks
141
+ end
142
+
143
+ if hooks
144
+ hooks.each do |cmd|
145
+ begin
146
+ SmallWonder::Log.info("Running #{type} deploy hook, command: #{cmd}")
147
+ output = `#{cmd} \'#{data_json}\'`
148
+ SmallWonder::Log.debug("#{type} deploy hook output:")
149
+ SmallWonder::Log.debug(output)
150
+ rescue Exception => e
151
+ SmallWonder::Log.fatal("#{type} deploy hook failed, command: #{cmd}, data: #{data_json}")
152
+ end
153
+ end
154
+ end
155
+
156
+ end
157
+
74
158
  ## deploy step
75
159
  # Creates a new salticid host for node, and calls <app>.deploy on it.
76
160
  def self.run_salticid_task(action, application, sudo_password)
@@ -36,27 +36,5 @@ module SmallWonder
36
36
  end
37
37
  end
38
38
 
39
- def self.sane_working_dir?(dir)
40
- sane = []
41
- sane << starts_with?(dir, "/tmp/small_wonder")
42
-
43
- if dir.include?("..")
44
- sane << false
45
- else
46
- sane << true
47
- end
48
-
49
- if sane.include?(false)
50
- false
51
- else
52
- true
53
- end
54
- end
55
-
56
- def self.starts_with?(string, prefix)
57
- prefix = prefix.to_s
58
- string[0, prefix.length] == prefix
59
- end
60
-
61
39
  end
62
- end
40
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: small_wonder
3
3
  version: !ruby/object:Gem::Version
4
- hash: 23
4
+ hash: 21
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 1
9
- - 6
10
- version: 0.1.6
9
+ - 7
10
+ version: 0.1.7
11
11
  platform: ruby
12
12
  authors:
13
13
  - Joe Williams
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-08-20 00:00:00 Z
18
+ date: 2012-10-05 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: mixlib-config