pot 0.1.0

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 (47) hide show
  1. checksums.yaml +15 -0
  2. data/CREDITS +32 -0
  3. data/LICENSE +20 -0
  4. data/README.md +21 -0
  5. data/bin/pot-console +9 -0
  6. data/lib/pot.rb +17 -0
  7. data/lib/pot/actor.rb +34 -0
  8. data/lib/pot/bundle.rb +66 -0
  9. data/lib/pot/config.rb +33 -0
  10. data/lib/pot/console.rb +7 -0
  11. data/lib/pot/deployment.rb +91 -0
  12. data/lib/pot/dsl.rb +39 -0
  13. data/lib/pot/installer.rb +131 -0
  14. data/lib/pot/installers/apt.rb +52 -0
  15. data/lib/pot/installers/binary.rb +46 -0
  16. data/lib/pot/installers/brew.rb +34 -0
  17. data/lib/pot/installers/deb.rb +41 -0
  18. data/lib/pot/installers/gem.rb +64 -0
  19. data/lib/pot/installers/group.rb +15 -0
  20. data/lib/pot/installers/npm.rb +19 -0
  21. data/lib/pot/installers/push_text.rb +49 -0
  22. data/lib/pot/installers/rake.rb +37 -0
  23. data/lib/pot/installers/replace_text.rb +45 -0
  24. data/lib/pot/installers/runner.rb +20 -0
  25. data/lib/pot/installers/source.rb +202 -0
  26. data/lib/pot/installers/transfer.rb +184 -0
  27. data/lib/pot/installers/user.rb +15 -0
  28. data/lib/pot/instance.rb +21 -0
  29. data/lib/pot/logger.rb +41 -0
  30. data/lib/pot/package.rb +352 -0
  31. data/lib/pot/policy.rb +74 -0
  32. data/lib/pot/role.rb +16 -0
  33. data/lib/pot/template.rb +20 -0
  34. data/lib/pot/transports/local.rb +31 -0
  35. data/lib/pot/transports/ssh.rb +81 -0
  36. data/lib/pot/verifiers/apt.rb +21 -0
  37. data/lib/pot/verifiers/brew.rb +21 -0
  38. data/lib/pot/verifiers/directory.rb +16 -0
  39. data/lib/pot/verifiers/executable.rb +53 -0
  40. data/lib/pot/verifiers/file.rb +34 -0
  41. data/lib/pot/verifiers/process.rb +21 -0
  42. data/lib/pot/verifiers/ruby.rb +25 -0
  43. data/lib/pot/verifiers/symlink.rb +30 -0
  44. data/lib/pot/verifiers/users_groups.rb +33 -0
  45. data/lib/pot/verify.rb +112 -0
  46. data/lib/pot/version.rb +13 -0
  47. metadata +118 -0
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ Njk1ODRkYzQ4Nzk3NGE0YWJiZDdhNTA2NDI0OWNkNjZmZGM3ZmM3OQ==
5
+ data.tar.gz: !binary |-
6
+ Njg4MjYxMTQ0ZGRkNDFiNzZkYTU4OTA0YjMxMTUxMzc0ZGZkMGI2Mw==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ ZDQwMmQ5ZDExYTNjOWJkOTA5NWYwOGI0ZDEwZWNmNGI5NGQ5NjYyYmY5ZGM2
10
+ YjI0YjA4OGUwNjE5NDlhNGQwYjI4ZjRlNzIzM2VjYmEyNDYyMmM3MThlNTVj
11
+ Y2I0NzdmNzI0MmEyNGM5NzNjOTIxMmZmY2Y3YTNlYjExMzMyZTY=
12
+ data.tar.gz: !binary |-
13
+ Y2MzMjJiZGJhY2MyNzdiN2ZjNDYzN2JlNTc2ZjM0MjdkMTYwMzRmNDJmNDU5
14
+ NGZjZDY1YWZjOTQ1NjU0NTBjYjIwOTg4Mzk1Yzc4MzE2MzlhODVlZDZkYjRj
15
+ NGJiMzkxYzA5NTc2M2JmN2M4ODc4NGJhNWRkZDQ2Y2I1ZmI2MGY=
data/CREDITS ADDED
@@ -0,0 +1,32 @@
1
+ = CREDITS
2
+
3
+ Marcus Crafter (https://github.com/crafterm)
4
+ Kristin Baumann (http://crafterm.net/kristin/blog/)
5
+ Ben Schwarz (http://germanforblack.com/)
6
+ Jim Freeze (http://www.artima.com/rubycs/articles/ruby_as_dslP.html)
7
+ Matthew Tanase (http://www.slicehost.com)
8
+ Jared Kuolt (http://www.slicehost.com)
9
+ Jamis Buck (http://www.capify.org)
10
+ Matt Allen (http://blog.allen.com.au)
11
+ Eric Hodel (http://blog.segment7.net)
12
+ Pete Yandell (http://notahat.com)
13
+ Adam Meehan (http://duckpunching.com)
14
+ Mitchell Hashimoto (http://mitchellhashimoto.com)
15
+ Ari Lerner (http://www.citrusbyte.com)
16
+ Jorgen Orehøj Erichsen (http://blog.erichsen.net)
17
+ Joshua Sierles (http://diluvia.net)
18
+ Julian Russell (http://github.com/plusplus)
19
+ Dave (Gassto) (http://github.com/gassto)
20
+ Bodaniel Jeanes (http://bjeanes.github.com)
21
+ Jacob Harris (http://open.nytimes.com)
22
+ Justin Pease (http://jit.nuance9.com)
23
+ Tobias Lütke (http://blog.leetsoft.com)
24
+ Josh Reynolds (http://github.com/jreynolds)
25
+ Jan Ulbrich (http://www.ulbrich.net)
26
+ Chris Gaffney (http://github.com/gaffneyc)
27
+ Maxmpz (http://github.com/maxmpz)
28
+ Geoff Garside (http://geoffgarside.co.uk/)
29
+ Oliver Kiessler (http://inceedo.com)
30
+ Nick Plante (http://blog.zerosum.org)
31
+
32
+ The transfer installer contains a piece of exception reporting code copied from the Chef library (http://wiki.opscode.com/display/chef/Home)
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ The MIT License
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ 'Software'), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,21 @@
1
+ # POT
2
+
3
+ ## DESCRIPTION:
4
+
5
+ Pot is a software provisioning tool.
6
+
7
+ Pot is based and inspired by <http://github.com/crafterm/sprinkle>.
8
+ Original code is copyrighted by Marcus Crafter <crafterm@redartisan.com>
9
+
10
+ Pot use sprinkle package system, but with new approach to deploy.
11
+
12
+ Pot is a work in progress.
13
+
14
+ ## CREDITS:
15
+ See CREDITS
16
+
17
+ ## LICENSE:
18
+
19
+ Copyright © 2013 ingeniarius
20
+
21
+ See MIT-LICENSE
data/bin/pot-console ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+ irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
3
+
4
+ libs = " -r irb/completion"
5
+ libs << " -I #{File.expand_path(__FILE__) + '/../../lib'}"
6
+ libs << " -r pot.rb"
7
+ libs << " -r pot/console.rb"
8
+ puts "Loading Pot"
9
+ exec "#{irb} #{libs} --simple-prompt"
data/lib/pot.rb ADDED
@@ -0,0 +1,17 @@
1
+ require 'pot/version'
2
+ require 'pot/config'
3
+ require 'pot/logger'
4
+ require 'pot/template'
5
+ require 'pot/instance'
6
+ require 'pot/actor'
7
+ require 'pot/verify'
8
+ require 'pot/package'
9
+ require 'pot/bundle'
10
+ require 'pot/policy'
11
+ require 'pot/installer'
12
+ require 'pot/transports/ssh'
13
+ require 'pot/transports/local'
14
+ require 'pot/deployment'
15
+
16
+ Dir[File.dirname(__FILE__) + '/pot/verifiers/*.rb'].each { |e| require e }
17
+ Dir[File.dirname(__FILE__) + '/pot/installers/*.rb'].each { |e| require e }
data/lib/pot/actor.rb ADDED
@@ -0,0 +1,34 @@
1
+ module Pot
2
+ class Actor
3
+
4
+ def initialize(instance, options = {})
5
+ @transport = Pot::Transports::Ssh.new(instance)
6
+ @sudo = !!options[:sudo]
7
+ end
8
+
9
+ def execute(commands)
10
+ commands.each do |command|
11
+ command = "sudo #{command}" if @sudo
12
+ @transport.execute(command)
13
+ end
14
+ end
15
+
16
+ def install(installer)
17
+ execute(installer.commands)
18
+ end
19
+
20
+ def verify(verifier)
21
+ command = verifier.commands.join(" && ")
22
+ @transport.execute(command) == 0
23
+ end
24
+
25
+ def transfer(source, destination, recursive = true)
26
+ @transport.transfer(source, destination, recursive)
27
+ end
28
+
29
+ def teardown
30
+ @transport if @transport.respond_to?(:teardown)
31
+ end
32
+
33
+ end
34
+ end
data/lib/pot/bundle.rb ADDED
@@ -0,0 +1,66 @@
1
+ module Pot
2
+ class Bundle
3
+
4
+ class UndefinedPackage < ::StandardError
5
+ def message
6
+ "Package definition not found for key: #{@message}"
7
+ end
8
+ end
9
+
10
+ def initialize(packages = [])
11
+ @packages = [packages].flatten
12
+ end
13
+
14
+ def list
15
+ all = []
16
+
17
+ @packages.each do |package_name|
18
+ cloud_info "Requires package #{package_name}\n"
19
+
20
+ package = Pot::Package::REGISTER[package_name]
21
+ raise UndefinedPackage, package_name unless package
22
+ package = select_package(package_name, package) if package.is_a? Array # handle virtual package selection
23
+
24
+ tree = package.tree do |parent, child, depth|
25
+ indent = "\t" * depth; cloud_info "#{indent}Package #{parent.name} requires #{child.name}"
26
+ end
27
+
28
+ all << tree
29
+ end
30
+
31
+ normalize(all)
32
+ end
33
+
34
+ def add(package)
35
+ @packages << package
36
+ end
37
+
38
+ private
39
+
40
+ def cloud_info(message)
41
+ Pot.logger.info(message) if Pot.config.cloud or Pot.logger.debug?
42
+ end
43
+
44
+ def select_package(name, packages)
45
+ if packages.size <= 1
46
+ package = packages.first
47
+ else
48
+ package = choose do |menu|
49
+ menu.prompt = "Multiple choices exist for virtual package #{name}"
50
+ menu.choices *packages.collect(&:to_s)
51
+ end
52
+ package = Pot::Package::REGISTER[package]
53
+ end
54
+
55
+ cloud_info "Selecting #{package.to_s} for virtual package #{name}"
56
+
57
+ package
58
+ end
59
+
60
+ def normalize(all, &block)
61
+ all = all.flatten.uniq
62
+ cloud_info "\n--> Normalized installation order for all packages: #{all.collect(&:name).join(', ')}"
63
+ all.each &block
64
+ end
65
+ end
66
+ end
data/lib/pot/config.rb ADDED
@@ -0,0 +1,33 @@
1
+ require 'singleton'
2
+
3
+ module Pot
4
+ class Config
5
+ include Singleton
6
+
7
+ attr_accessor :testing,
8
+ :verbose,
9
+ :force,
10
+ :cloud,
11
+ :debug
12
+
13
+ def initialize
14
+ @testing = false
15
+ @verbose = false
16
+ @force = false
17
+ @debug = false
18
+ end
19
+
20
+ def testing?
21
+ @testing
22
+ end
23
+
24
+ def debug?
25
+ @debug
26
+ end
27
+
28
+ end
29
+
30
+ def self.config
31
+ Pot::Config.instance
32
+ end
33
+ end
@@ -0,0 +1,7 @@
1
+ require 'pot/dsl'
2
+
3
+ include Pot::DSL
4
+
5
+ Dir[Dir.pwd + '/packages/*.rb'].each { |e| require e }
6
+ Dir[Dir.pwd + '/policies/*.rb'].each { |e| require e }
7
+ Dir[Dir.pwd + '/instances/*.rb'].each { |e| require e }
@@ -0,0 +1,91 @@
1
+ module Pot
2
+ class Deployment
3
+
4
+ class UndefinedInstance < ::StandardError
5
+ def message
6
+ "Instance definition not found for key: #{@message}"
7
+ end
8
+ end
9
+
10
+ class UndefinedPolicy < ::StandardError
11
+ def message
12
+ "Policy definition not found for key: #{@message}"
13
+ end
14
+ end
15
+
16
+ def initialize(options = {})
17
+ @options = options
18
+ end
19
+
20
+ def execute_on_instances(commands, instance_name)
21
+ instances = find_instances(instance_names)
22
+ deploy_to_instances(instances) do |actor|
23
+ actor.execute(commands)
24
+ end
25
+ end
26
+
27
+ def deploy_policies_to_instances(police_names, instance_names)
28
+ policies = find_policies(police_names)
29
+ instances = find_instances(instance_names)
30
+ deploy_policies_to_instances_internal(policies, instances)
31
+ end
32
+
33
+ def deploy_packages_to_instances(package_names, instance_names)
34
+ package_tree = Pot::Bundle.new(package_names)
35
+ instances = find_instances(instance_names)
36
+ deploy_to_instances(instances) do |actor|
37
+ package_tree.list.each do |package|
38
+ package.process(actor)
39
+ end
40
+ end
41
+ end
42
+
43
+ def deploy_roles(roles)
44
+ roles = roles.map(&:to_sym)
45
+ instances = []
46
+ Pot::Role::REGISTER.each do |role_name, instance|
47
+ instances << instance if roles.include?(role_name)
48
+ end
49
+ policies = []
50
+ Pot::Policy::REGISTER.each do |policy_name, policy|
51
+ policy_roles = [policy.roles].flatten
52
+ policies << policy unless (policy_roles & roles).empty?
53
+ end
54
+ deploy_policies_to_instances_internal(policies, instances)
55
+ end
56
+
57
+ private
58
+
59
+ def find_policies(police_names)
60
+ [police_names].flatten.map do |policy_name|
61
+ policy = Pot::Policy::REGISTER[policy_name.to_sym]
62
+ raise UndefinedPolicy, policy_name unless policy
63
+ policy
64
+ end
65
+ end
66
+
67
+ def find_instances(instance_names)
68
+ [instance_names].flatten.map do |instance_name|
69
+ instance = Pot::Instance::REGISTER[instance_name.to_sym]
70
+ raise UndefinedInstance, instance_name unless instance
71
+ instance
72
+ end
73
+ end
74
+
75
+ def deploy_policies_to_instances_internal(policies, instances)
76
+ deploy_to_instances(instances) do |actor|
77
+ policies.each do |policy|
78
+ policy.process(actor)
79
+ end
80
+ end
81
+ end
82
+
83
+ def deploy_to_instances(instances)
84
+ instances.each do |instance|
85
+ actor = Pot::Actor.new(instance, @options)
86
+ yield actor
87
+ end
88
+ end
89
+
90
+ end
91
+ end
data/lib/pot/dsl.rb ADDED
@@ -0,0 +1,39 @@
1
+ module Pot
2
+ module DSL # :nodoc: all
3
+ def set(option, value)
4
+ Pot::Config.instance.send("#{option}=", value)
5
+ end
6
+
7
+ def instance(name, host, options = {})
8
+ Pot::Instance.new(name, host, options)
9
+ end
10
+
11
+ def package(name, metadata = {}, &block)
12
+ Pot::Package.new(name, metadata, &block)
13
+ end
14
+
15
+ def policy(name, options = {}, &block)
16
+ Pot::Policy.new(name, options, &block)
17
+ end
18
+
19
+ def role(role_name, instance_name)
20
+ Pot::Role.new(role_name, instance_name)
21
+ end
22
+
23
+ def deploy_policies(instances, policies, options = {})
24
+ deployment = Pot::Deployment.new(options)
25
+ deployment.deploy_policies_to_instances(policies, instances)
26
+ end
27
+
28
+ def deploy_packages(instances, packages, options = {})
29
+ deployment = Pot::Deployment.new(options)
30
+ deployment.deploy_packages_to_instances(packages, instances)
31
+ end
32
+
33
+ def deploy_roles(roles, options = {})
34
+ deployment = Pot::Deployment.new(options)
35
+ deployment.deploy_roles(roles)
36
+ end
37
+
38
+ end
39
+ end
@@ -0,0 +1,131 @@
1
+ module Pot
2
+ # Based on ...
3
+ # Copyright (c) 2008-2009 Marcus Crafter crafterm@redartisan.com
4
+ #
5
+ # The base class which all installers must subclass, this class makes
6
+ # sure all installers share some general features, which are outlined
7
+ # below.
8
+ #
9
+ # = Pre/Post Installation Hooks
10
+ #
11
+ # With all installation methods you have the ability to specify multiple
12
+ # pre/post installation hooks. This gives you the ability to specify
13
+ # commands to run before and after an installation takes place. All
14
+ # commands by default are sudo'd so there is no need to include "sudo"
15
+ # in the command itself. There are three ways to specify a pre/post hook.
16
+ #
17
+ # First, a single command:
18
+ #
19
+ # pre :install, 'echo "Hello, World!"'
20
+ # post :install, 'rm -rf /'
21
+ #
22
+ # Second, an array of commands:
23
+ #
24
+ # commands = ['echo "First"', 'echo "Then Another"']
25
+ # pre :install, commands
26
+ # post :install, commands
27
+ #
28
+ # Third, a block which returns either a single or multiple commands:
29
+ #
30
+ # pre :install do
31
+ # amount = 7 * 3
32
+ # "echo 'Before we install, lets plant #{amount} magic beans...'"
33
+ # end
34
+ # post :install do
35
+ # ['echo "Now... let's hope they sprout!", 'echo "Indeed they have!"']
36
+ # end
37
+ #
38
+ # = Other Pre/Post Hooks
39
+ #
40
+ # Some installation methods actually grant you more fine grained
41
+ # control of when commands are run rather than a blanket pre :install
42
+ # or post :install. If this is the case, it will be documented on
43
+ # the installation method's corresponding documentation page.
44
+ class Installer
45
+ attr_accessor :actor, :package, :options, :pre, :post #:nodoc:
46
+
47
+ def initialize(package, options = {}, &block) #:nodoc:
48
+ @package = package
49
+ @options = options
50
+ @pre = {}
51
+ @post = {}
52
+ self.instance_eval(&block) if block
53
+ end
54
+
55
+ def pre(stage, *commands)
56
+ @pre[stage] ||= []
57
+ @pre[stage] += commands
58
+ @pre[stage] += [yield] if block_given?
59
+ end
60
+
61
+ def post(stage, *commands)
62
+ @post[stage] ||= []
63
+ @post[stage] += commands
64
+ @post[stage] += [yield] if block_given?
65
+ end
66
+
67
+ def prefix(prefix)
68
+ @options[:prefix] = prefix
69
+ end
70
+
71
+ def archives(archives)
72
+ @options[:archives] = archives
73
+ end
74
+
75
+ def builds(builds)
76
+ @options[:builds] = builds
77
+ end
78
+
79
+ def process(actor) #:nodoc:
80
+ if Pot.logger.debug?
81
+ sequence = commands;
82
+ sequence = sequence.join('; ') if sequence.is_a? Array
83
+ Pot.logger.debug "#{@package.name} install sequence: #{sequence}\n"
84
+ end
85
+
86
+ unless Pot.config.testing?
87
+ Pot.logger.info "--> Installing #{package.name}"
88
+ actor.install(self)
89
+ end
90
+ end
91
+
92
+ # More complicated installers that have different stages, and require pre/post commands
93
+ # within stages can override commands and take complete control of the install
94
+ # command sequence construction (eg. source based installer).
95
+ def commands
96
+ commands = pre_commands(:install) + [ install_commands ] + post_commands(:install)
97
+ commands.flatten
98
+ end
99
+
100
+ protected
101
+ # A concrete installer (subclass of this virtual class) must override this method
102
+ # and return the commands it needs to run as either a string or an array.
103
+ #
104
+ # <b>Overriding this method is required.</b>
105
+ def install_commands
106
+ raise 'Concrete installers implement this to specify commands to run to install their respective packages'
107
+ end
108
+
109
+ def pre_commands(stage) #:nodoc:
110
+ dress @pre[stage] || [], :pre
111
+ end
112
+
113
+ def post_commands(stage) #:nodoc:
114
+ dress @post[stage] || [], :post
115
+ end
116
+
117
+ # Concrete installers (subclasses of this virtual class) can override this method to
118
+ # specify stage-specific (pre-installation, post-installation, etc.) modifications
119
+ # of commands.
120
+ #
121
+ # An example usage of overriding this would be to prefix all commands for a
122
+ # certain stage to change to a certain directory. An example is given below:
123
+ #
124
+ # def dress(commands, stage)
125
+ # commands.collect { |x| "cd #{magic_beans_path} && #{x}" }
126
+ # end
127
+ #
128
+ # By default, no modifications are made to the commands.
129
+ def dress(commands, stage); commands; end
130
+ end
131
+ end