ploy 0.0.4

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a2c78754ea6d6c007f064e3a182ae81f94e42c9a
4
+ data.tar.gz: 2a5591e5ae8c2ed1b6a96fed8f7bc9483deea231
5
+ SHA512:
6
+ metadata.gz: 182997ac859c97cd237fc9b73e24b6bc1a6715f82b3df85e8fd1e1c4c32106133957c803d286fd4d8739be306b29ec49cdd7fd862000431cddcb9a5781422c2a
7
+ data.tar.gz: b3ec95b355a8a8fcd6402c73bd33dc0ba3a0923bdc201f31156aa8f44e9b2842078a9ea8387cd6a04b0291b833467d928e2c60f18d1c0e98ba1271533767873b
data/bin/ploy ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'ploy/cli'
4
+
5
+ Ploy::Cli.new.run ARGV
6
+
data/lib/ploy/cli.rb ADDED
@@ -0,0 +1,10 @@
1
+ require 'ploy/command'
2
+
3
+ module Ploy
4
+ class Cli
5
+ def run(argv)
6
+ subcommand = argv.shift || 'help'
7
+ Ploy::Command.lookup(subcommand).run(argv)
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,22 @@
1
+ require 'ploy/command/install'
2
+ require 'ploy/command/publish'
3
+ require 'ploy/command/help'
4
+ require 'ploy/command/bless'
5
+ require 'ploy/command/oracle'
6
+
7
+ module Ploy
8
+ module Command
9
+ def self.lookup(topic)
10
+ lookup = {
11
+ 'install' => Ploy::Command::Install,
12
+ 'bless' => Ploy::Command::Bless,
13
+ 'help' => Ploy::Command::Help,
14
+ 'publish' => Ploy::Command::Publish,
15
+ 'oracle' => Ploy::Command::Oracle,
16
+ }
17
+ mod = lookup[topic] || lookup['help']
18
+ return mod.new
19
+ end
20
+ end
21
+ end
22
+
@@ -0,0 +1,14 @@
1
+ module Ploy
2
+ module Command
3
+ class Base
4
+ def run(argv)
5
+ return false
6
+ end
7
+
8
+ def help
9
+ return ""
10
+ end
11
+ end
12
+ end
13
+ end
14
+
@@ -0,0 +1,68 @@
1
+ require 'ploy/command/base'
2
+ require 'ploy/package'
3
+ require 'json'
4
+
5
+ module Ploy
6
+ module Command
7
+ class Bless < Base
8
+ def run(argv)
9
+ o = {}
10
+ optparser(o).parse!(argv)
11
+ pkgs = []
12
+ if (o[:datapath]) then
13
+ pkgs = Ploy::Package.from_metadata(o[:bucket], JSON.parse(File.read(o[:datapath])))
14
+ else
15
+ pkgs.push Ploy::Package.new(o[:bucket], o[:deploy], o[:branch], o[:version])
16
+ end
17
+
18
+ pkgs.each do |pkg|
19
+ pkg.bless
20
+ puts "blessed #{o[:deploy]}/#{o[:branch]} at #{o[:version]}"
21
+ end
22
+ end
23
+
24
+ def help
25
+ return <<helptext
26
+ usage: ploy -b BUCKET [-d DEPLOYMENT -B BRANCH -v VERSION | -f DATAFILE]
27
+
28
+ #{optparser}
29
+
30
+ Examples:
31
+ $ ploy bless -b deploybucket -d someproject -B master -v 6d4a094dcaad6e421f85b24c7c75153db72ab00c
32
+ $ ploy bless -b deploybucket -f /tmp/version_info.json
33
+
34
+ Summary
35
+
36
+ The bless command takes action to verify that specific package is "blessed" to go to production.
37
+ It should only be marked as such after a successful run through unit, integration and smoke
38
+ tests.
39
+
40
+ helptext
41
+ end
42
+
43
+ private
44
+ def optparser(o = {})
45
+ options = OptionParser.new do |opts|
46
+ opts.banner = ''
47
+ opts.on("-b", "--bucket BUCKET", "use the given S3 bucket") do |bucket|
48
+ o[:bucket] = bucket
49
+ end
50
+ opts.on("-d", "--deployment DEPLOYMENT", "bless the given deployment (project)") do |dep|
51
+ o[:deploy] = dep
52
+ end
53
+ opts.on("-B", "--branch BRANCH", "use the deployment from the given branch") do |branch|
54
+ o[:branch] = branch
55
+ end
56
+ opts.on("-v", "--version VERSION", "use the given version") do |v|
57
+ o[:version] = v
58
+ end
59
+ opts.on("-f", "--data-file PATH", "load a set of dep/branch/version data from a", "version file compatible with ploy oracle output") do |path|
60
+ o[:datapath] = path
61
+ end
62
+ end
63
+ return options
64
+ end
65
+
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,23 @@
1
+ require 'ploy/command/base'
2
+
3
+ module Ploy
4
+ module Command
5
+ class Help < Base
6
+ def run(argv)
7
+ puts Ploy::Command.lookup(argv.shift).help
8
+ end
9
+ def help
10
+ return <<helptext
11
+ usage: ploy [command] [options]
12
+
13
+ Commands:
14
+ publish Package the current git repository and send to S3
15
+ install Pull a deployment from S3 and install on current system
16
+ bless Mark a package as tested for production use
17
+ help Show helps
18
+
19
+ helptext
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,68 @@
1
+ require 'ploy/command/base'
2
+ require 'optparse'
3
+ require 'ploy/package'
4
+
5
+ module Ploy
6
+ module Command
7
+ class Install < Base
8
+ def run(argv)
9
+ o = {
10
+ :version => 'current',
11
+ :branch => 'master',
12
+ :check => true,
13
+ }
14
+ optparser(o).parse!(argv)
15
+ pkg = Ploy::Package.new(o[:bucket], o[:deploy], o[:branch], o[:version])
16
+ if (!o[:check] || pkg.check_new_version)
17
+ pkg.install()
18
+ puts "installed #{o[:deploy]}"
19
+ else
20
+ puts "no new version available"
21
+ end
22
+ return true
23
+ end
24
+
25
+ def help
26
+ return <<helptext
27
+ usage: ploy install -b $bucket -d $deployment -B $branch -v $version
28
+
29
+ #{optparser}
30
+
31
+ Examples:
32
+ $ ploy install -b deploybucket -d someproject # default to master branch and current version
33
+ $ ploy install -b deploybucket -d someproject -B master -v current
34
+ $ ploy install -b deploybucket -d someproject -B master -v 6d4a094dcaad6e421f85b24c7c75153db72ab00c
35
+
36
+ Summary:
37
+
38
+ The install command will download and install a package that matches the
39
+ specification given on the command line. If the available version has the
40
+ same git revision as a currently installed version, it will do nothing.
41
+
42
+ helptext
43
+
44
+ end
45
+
46
+ private
47
+ def optparser(o = {})
48
+ options = OptionParser.new do |opts|
49
+ opts.banner = ''
50
+ opts.on("-b", "--bucket BUCKET", "use the given S3 bucket") do |bucket|
51
+ o[:bucket] = bucket
52
+ end
53
+ opts.on("-d", "--deployment DEPLOYMENT", "install the given deployment (project)") do |dep|
54
+ o[:deploy] = dep
55
+ end
56
+ opts.on("-B", "--branch BRANCH", "use the deployment from the given branch") do |branch|
57
+ o[:branch] = branch
58
+ end
59
+ opts.on("-v", "--version VERSION", "use the given version") do |v|
60
+ o[:version] = v
61
+ end
62
+ end
63
+ return options
64
+ end
65
+
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,48 @@
1
+ require 'sinatra'
2
+ require 'json'
3
+ require 'ploy/metasrc'
4
+
5
+ # TODO: this needs tests. It is a Friday; I just don't have the brainpower
6
+ # left to figure out how to test a subclassed sinatra.
7
+
8
+ module Ploy
9
+ module Command
10
+ class OracleServer < Sinatra::Base
11
+ set :port => 9876
12
+ set :bind => '0.0.0.0'
13
+
14
+ def self.oracle_run(metasrc)
15
+ @@metasrc = metasrc # this could not be sadder
16
+ run!
17
+ end
18
+ get '/' do
19
+ [
20
+ 200,
21
+ { "Content-type" => "text/json" },
22
+ JSON.dump(@@metasrc.load)
23
+ ]
24
+ end
25
+ end
26
+ class Oracle < Base
27
+ def run(argv)
28
+ OracleServer.oracle_run Ploy::MetaSrc.new(argv.shift || '/etc/ploy/metadata.d')
29
+ end
30
+ def help
31
+ return <<helptext
32
+ usage: ploy oracle [dir]
33
+
34
+ Examples:
35
+
36
+ $ ploy oracle /etc/ploy/metadata.d
37
+
38
+ Summary:
39
+
40
+ The oracle command starts up an http server. When it receives a GET request, it
41
+ will read all of the metadata files in [dir] and return the data in them to
42
+ the client as json.
43
+
44
+ helptext
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,42 @@
1
+ require 'ploy/command/base'
2
+ require 'ploy/publisher'
3
+
4
+ module Ploy
5
+ module Command
6
+ class Publish < Base
7
+ def run(argv)
8
+ Ploy::Publisher.new(argv.shift || '.ploy-publisher.yml').publish
9
+ puts "ploy publish ok"
10
+ return true
11
+ end
12
+
13
+ def help
14
+ return <<helptext
15
+ usage: ploy publish [config.yml]
16
+
17
+ Examples:
18
+
19
+ $ ploy publish
20
+ $ ploy publish something.yml
21
+
22
+ Config Example:
23
+
24
+ ---
25
+ bucket: bucketname
26
+ deploy_name: some-project
27
+ dist_dir: spec/resources/dist
28
+ prep_cmd: lineman build
29
+ prefix: /usr/local/someproject
30
+ upstart_files:
31
+ - spec/resources/conf/some-project-initfile
32
+
33
+ Summary:
34
+
35
+ The publish command takes a config YAML file as input, and uses that to construct a
36
+ debian package file and push it into a particular location in S3
37
+
38
+ helptext
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,17 @@
1
+ module Ploy
2
+ module Util
3
+
4
+ def Util.remote_name(deploy,branch,rev, blessed = false)
5
+ r = [
6
+ deploy,
7
+ branch,
8
+ "#{deploy}_#{rev}.deb"
9
+ ]
10
+ if (blessed) then
11
+ r.unshift('blessed')
12
+ end
13
+ return r.join('/')
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,53 @@
1
+ require 'ploy/localpackage/debbuilder'
2
+
3
+ module Ploy
4
+ module LocalPackage
5
+ class Config
6
+ def initialize(conf_source = '.ploy-publisher.yml')
7
+ @conf = conf_source
8
+ if (/^---/ =~ conf_source) then
9
+ @conf = YAML::load(conf_source)
10
+ else
11
+ @conf = YAML::load_file(conf_source)
12
+ end
13
+ end
14
+
15
+ def builder
16
+ builder = Ploy::LocalPackage::DebBuilder.new(
17
+ :name => @conf['deploy_name'],
18
+ :sha => git_revision,
19
+ :branch => git_branch,
20
+ :timestamp => git_timestamp,
21
+ :upstart_files => @conf['upstart_files'],
22
+ :dist_dir => @conf['dist_dir'],
23
+ :prefix => @conf['prefix'],
24
+ :prep_cmd => @conf['prep_cmd']
25
+ );
26
+ return builder
27
+ end
28
+
29
+ def remote_package
30
+ return Ploy::Package.new(
31
+ @conf['bucket'],
32
+ @conf['deploy_name'],
33
+ git_branch,
34
+ git_revision
35
+ )
36
+ end
37
+
38
+ private
39
+ def git_branch
40
+ return ENV['TRAVIS_BRANCH'] || `git symbolic-ref --short -q HEAD`.chomp
41
+ end
42
+
43
+ def git_revision
44
+ return `git rev-parse HEAD`.chomp
45
+ end
46
+
47
+ def git_timestamp
48
+ return `git log -1 --pretty=format:"%ct"`
49
+ end
50
+
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,77 @@
1
+ require 'yaml'
2
+ require 'ploy/localpackage/optlist'
3
+
4
+ module Ploy
5
+ module LocalPackage
6
+ class DebBuilder
7
+ attr_accessor :name
8
+ attr_accessor :sha
9
+ attr_accessor :branch
10
+ attr_accessor :timestamp
11
+ attr_accessor :upstart_files
12
+ attr_accessor :dist_dir
13
+ attr_accessor :prefix
14
+
15
+ def initialize(opts = {})
16
+ @metadata_dir = "/etc/ploy/metadata.d"
17
+ opts.each { |k,v| instance_variable_set("@#{k}", v) } # maybe?
18
+ end
19
+
20
+ def build_deb
21
+ info = nil
22
+ Dir.mktmpdir do |dir|
23
+ mirror_dist(dir)
24
+ write_metadata(dir)
25
+ info = eval(`fpm #{fpm_optlist(dir).as_string} .`)
26
+ end
27
+ return info[:path]
28
+ end
29
+
30
+ def fpm_optlist(dir)
31
+ optlist = Ploy::LocalPackage::DebBuilderOptlist.new [
32
+ { "-n" => @name },
33
+ { "-s" => "dir" },
34
+ { "-t" => "deb" },
35
+ { "-a" => "all" },
36
+ { "-C" => dir },
37
+ { "--deb-field" => "'gitrev: #{@sha}'" },
38
+ "-f",
39
+ { "-v" => @timestamp + '.' + @branch },
40
+ ]
41
+
42
+ if @upstart_files then
43
+ @upstart_files.each do | upstart |
44
+ optlist.add("--deb-upstart", upstart)
45
+ end
46
+ end
47
+
48
+ return optlist
49
+ end
50
+
51
+ def mirror_dist(dir)
52
+ FileUtils.mkpath mirror_dist_target(dir)
53
+ system("rsync -aC #{@dist_dir}/* #{mirror_dist_target(dir)}")
54
+ end
55
+
56
+ def mirror_dist_target(topdir)
57
+ return @prefix ? File.join(topdir, @prefix) : topdir
58
+ end
59
+
60
+ def write_metadata(dir)
61
+ base = File.join(dir, @metadata_dir)
62
+ FileUtils.mkpath(base)
63
+ path = File.join(base, "#{@name}.yml")
64
+ info = {
65
+ "name" => @name,
66
+ "sha" => @sha,
67
+ "timestamp" => @timestamp,
68
+ "branch" => @branch,
69
+ }
70
+ File.open(path, 'w') do | out |
71
+ YAML.dump(info, out)
72
+ end
73
+
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,30 @@
1
+ module Ploy
2
+ module LocalPackage
3
+ class DebBuilderOptlist
4
+ @list = []
5
+ def initialize(list = [])
6
+ @list = list
7
+ end
8
+
9
+ def add(switch, val = nil)
10
+ opt = val != nil ? { switch => val } : switch
11
+ @list.push(opt)
12
+ end
13
+
14
+ def as_string
15
+ opts_flat = []
16
+
17
+ @list.each do | e |
18
+ if (e.is_a? Hash) then
19
+ e.each { | k, v| opts_flat.push([k,v].join(' ')) }
20
+ else
21
+ opts_flat.push(e)
22
+ end
23
+ end
24
+
25
+ return opts_flat.join(' ')
26
+ end
27
+
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,17 @@
1
+ module Ploy
2
+ class MetaSrc
3
+ def initialize(dir)
4
+ @dir = dir
5
+ end
6
+ def load
7
+ d = {}
8
+ Dir.foreach(@dir) do |fname|
9
+ if (fname =~ /\.ya?ml$/) then
10
+ y = YAML::load_file(File.join(@dir,fname))
11
+ d[y['name']] = y
12
+ end
13
+ end
14
+ return d
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,61 @@
1
+ require 'ploy/common'
2
+ require 'ploy/s3storage'
3
+
4
+ module Ploy
5
+ class Package
6
+ attr_accessor :deploy_name
7
+ attr_accessor :branch
8
+ attr_accessor :version
9
+
10
+ def initialize(bucket, deploy, branch, version)
11
+ @deploy_name = deploy
12
+ @branch = branch
13
+ @version = version
14
+
15
+ @store = Ploy::S3Storage.new(bucket)
16
+ end
17
+
18
+ def check_new_version
19
+ installed = `dpkg-query -W -f '${gitrev}' #{@deploy_name}`.chomp
20
+ remote_v = @store.metadata(location)['git_revision']
21
+ return (installed != remote_v)
22
+ end
23
+
24
+ def install
25
+ Tempfile.open(['ploy', '.deb']) do |f|
26
+ @store.get(location, f)
27
+ system("dpkg -i #{f.path}")
28
+ end
29
+ end
30
+
31
+ def bless
32
+ @store.copy(
33
+ location,
34
+ Ploy::Util.remote_name(@deploy_name, @branch, @version, true)
35
+ )
36
+ end
37
+
38
+ def location
39
+ return Ploy::Util.remote_name(@deploy_name, @branch, @version)
40
+ end
41
+ def location_current
42
+ return Ploy::Util.remote_name(@deploy_name, @branch, 'current')
43
+ end
44
+
45
+ def upload(path)
46
+ @store.put(path, location, {'git_revision' => @version})
47
+ end
48
+
49
+ def make_current
50
+ @store.copy(location, location_current)
51
+ end
52
+
53
+ def self.from_metadata(bucket, meta)
54
+ out = []
55
+ meta.each do |k,v|
56
+ out.push(self.new(bucket, v['name'], v['branch'], v['sha']))
57
+ end
58
+ return out
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,19 @@
1
+ require 'ploy/localpackage/config'
2
+
3
+ module Ploy
4
+ class Publisher
5
+ def initialize(conf_source)
6
+ @config = Ploy::LocalPackage::Config.new conf_source
7
+ end
8
+
9
+ def publish
10
+ pkgpath = @config.builder.build_deb
11
+ remote_package = @config.remote_package
12
+ remote_package.upload(pkgpath)
13
+ remote_package.make_current
14
+ return remote_package
15
+ end
16
+
17
+ end
18
+
19
+ end
@@ -0,0 +1,36 @@
1
+ require 'aws-sdk'
2
+
3
+ module Ploy
4
+ class S3Storage
5
+ def initialize(bucket)
6
+ @bucketname = bucket
7
+ end
8
+
9
+ def put(path, name, meta = {})
10
+ AWS::S3.new.buckets[@bucketname].objects[name].write(
11
+ Pathname.new(path),
12
+ { :metadata => meta },
13
+ )
14
+ end
15
+
16
+ def copy(from, to)
17
+ AWS::S3.new.buckets[@bucketname].objects[from].copy_to(to)
18
+ end
19
+
20
+ def get(from, fileio)
21
+ AWS::S3.new.buckets[@bucketname].objects[from].read do |chunk|
22
+ fileio.write(chunk)
23
+ end
24
+ fileio.flush
25
+ end
26
+
27
+ def metadata(loc)
28
+ o = AWS::S3.new.buckets[@bucketname].objects[loc]
29
+ if (o.exists?) then
30
+ return o.metadata
31
+ else
32
+ return {}
33
+ end
34
+ end
35
+ end
36
+ end
metadata ADDED
@@ -0,0 +1,102 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ploy
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.4
5
+ platform: ruby
6
+ authors:
7
+ - Michael Bruce
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-03-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: aws-sdk
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: fpm
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: sinatra
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: deployment
56
+ email: mbruce@manta.com
57
+ executables:
58
+ - ploy
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - lib/ploy/cli.rb
63
+ - lib/ploy/command/base.rb
64
+ - lib/ploy/command/bless.rb
65
+ - lib/ploy/command/help.rb
66
+ - lib/ploy/command/install.rb
67
+ - lib/ploy/command/oracle.rb
68
+ - lib/ploy/command/publish.rb
69
+ - lib/ploy/command.rb
70
+ - lib/ploy/common.rb
71
+ - lib/ploy/localpackage/config.rb
72
+ - lib/ploy/localpackage/debbuilder.rb
73
+ - lib/ploy/localpackage/optlist.rb
74
+ - lib/ploy/metasrc.rb
75
+ - lib/ploy/package.rb
76
+ - lib/ploy/publisher.rb
77
+ - lib/ploy/s3storage.rb
78
+ - bin/ploy
79
+ homepage:
80
+ licenses: []
81
+ metadata: {}
82
+ post_install_message:
83
+ rdoc_options: []
84
+ require_paths:
85
+ - lib
86
+ required_ruby_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - '>='
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ required_rubygems_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - '>='
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ requirements: []
97
+ rubyforge_project:
98
+ rubygems_version: 2.0.3
99
+ signing_key:
100
+ specification_version: 4
101
+ summary: deployment
102
+ test_files: []