small_wonder 0.1.6 → 0.1.7

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