deployku 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.
@@ -0,0 +1,139 @@
1
+ require 'fileutils'
2
+ require 'yaml'
3
+ require 'securerandom'
4
+ require 'open3'
5
+
6
+ module Deployku
7
+ class PostgresPlugin < Deployku::Plugin
8
+ include Deployku::Configurable
9
+ include Deployku::Containerable
10
+
11
+ def initialize
12
+ @config = {
13
+ 'from' => 'postgres',
14
+ 'env' => {}
15
+ }
16
+ end
17
+
18
+ describe :create, '<NAME>', 'creates new PostgreSQL instance', acl_sys: :admin
19
+ def create(name)
20
+ app_dir = dir(name)
21
+ unless Dir.exists?(app_dir)
22
+ FileUtils.mkdir_p(app_dir)
23
+ end
24
+ app_dir
25
+ end
26
+
27
+ describe :delete, '<NAME>', 'deletes an existing PostgreSQL instance', acl_sys: :admin
28
+ def delete(name)
29
+ app_dir = dir(name)
30
+ if Dir.exists?(app_dir)
31
+ FileUtils.rm_rf(app_dir)
32
+ end
33
+ end
34
+
35
+ describe :list, '', 'lists available PostgreSQL instances', acl_sys: :admin
36
+ def list
37
+ Dir.glob(File.join(Deployku::Config.home, '.postgres', '*')) do |path|
38
+ puts File.basename(path) if File.directory?(path)
39
+ end
40
+ end
41
+
42
+ describe 'db:create', '<NAME> <DB_NAME>', 'create a database in postgres instance', acl_sys: :admin
43
+ def db_create(name, db_name)
44
+ config_load(name)
45
+ cid = get_container_id(name)
46
+ unless Deployku::Engine.running?(cid)
47
+ puts "Database instance '#{name}' is not running."
48
+ exit 1
49
+ end
50
+ ip = Deployku::Engine.ip(cid)
51
+ db = Deployku.sanitize_app_name(db_name)
52
+ system "echo \"#{@config['env']['POSTGRES_PASSWORD']}\n\" 'CREATE DATABASE #{db};' | psql -h #{ip} -U postgres"
53
+ end
54
+
55
+ describe 'db:drop', '<NAME> <DB_NAME>', 'destroy a database in postgres instance', acl_sys: :admin
56
+ def db_drop(name, db_name)
57
+ config_load(name)
58
+ cid = get_container_id(name)
59
+ unless Deployku::Engine.running?(cid)
60
+ puts "Database instance '#{name}' is not running."
61
+ exit 1
62
+ end
63
+ ip = Deployku::Engine.ip(cid)
64
+ db = Deployku.sanitize_app_name(db_name)
65
+ system "echo \"#{@config['env']['POSTGRES_PASSWORD']}\n\" 'DROP DATABASE #{db};' | psql -h #{ip} -U postgres"
66
+ end
67
+
68
+ describe 'db:link', '<NAME> <DB_NAME> <APP>', 'connect appliaction with database', acl_sys: :admin
69
+ def db_link(name, db_name, app_name)
70
+ config_load(name)
71
+ db_id = get_container_id(name)
72
+ ip = Deployku::Engine.ip(db_id)
73
+ db = Deployku.sanitize_app_name(db_name)
74
+ user_name = 'user_' + SecureRandom.uuid.gsub('-','')
75
+ user_passwd = SecureRandom.uuid
76
+ database_url = "postgres://#{user_name}:#{user_passwd}@#{container_name(name)}/#{db}"
77
+ system "echo \"#{@config['env']['POSTGRES_PASSWORD']}\n\" \"CREATE USER #{user_name} WITH PASSWORD '#{user_passwd}';\" | psql -h #{ip} -U postgres"
78
+ system "echo \"#{@config['env']['POSTGRES_PASSWORD']}\n\" 'GRANT ALL ON DATABASE #{db} TO #{user_name};' | psql -h #{ip} -U postgres"
79
+ if $?.exitstatus == 0
80
+ Deployku::AppPlugin.run('config:set', [app_name, 'DATABASE_URL', database_url])
81
+ Deployku::AppPlugin.run(:link, [app_name, container_name(name)])
82
+ else
83
+ puts "Unable to create user in database."
84
+ exit 1
85
+ end
86
+ end
87
+
88
+ describe 'db:connect', '<NAME> <DB_NAME>', 'connect to database and enter prompt', acl_sys: :admin
89
+ def db_connect(name, db_name)
90
+ config_load(name)
91
+ db_id = get_container_id(name)
92
+ dbname = Deployku.sanitize_app_name(db_name)
93
+ ip = Deployku::Engine.ip(db_id)
94
+ system "PGPASSWORD=\"#{@config['env']['POSTGRES_PASSWORD']}\" psql -h #{ip} -U postgres #{dbname}"
95
+ end
96
+
97
+ # methods from containerable
98
+ describe :start, '<NAME>', 'starts container', acl_sys: :admin
99
+ def start(app_name)
100
+ config_load(app_name)
101
+ unless @config['volumes']
102
+ @config['volumes'] = {
103
+ File.join(dir(app_name), 'data') => '/postgresql/'
104
+ }
105
+ end
106
+ @config['env']['PGDATA'] = '/postgresql/' unless @config['env']['PGDATA']
107
+ @config['env']['POSTGRES_PASSWORD'] = SecureRandom.uuid unless @config['env']['POSTGRES_PASSWORD']
108
+ config_save(app_name)
109
+
110
+ Deployku::Config.merge!(@config)
111
+ app_hash = Deployku::Engine.start(@config['from'], dir(app_name), container_name(app_name))
112
+ exit 1 if $?.nil? || $?.exitstatus != 0
113
+ set_container_id(app_name, container_name(app_name))
114
+ puts "Container #{app_hash} started."
115
+ end
116
+
117
+ describe :status, '<NAME>', 'show container status', acl_sys: :admin
118
+ describe :stop, '<NAME>', 'stops running container', acl_sys: :admin
119
+ describe :restart, '<NAME>', 'restarts container', acl_sys: :admin
120
+ describe :logs, '<NAME>', 'show app logs', acl_sys: :admin
121
+
122
+ # methods from configurable
123
+ describe 'config:show', '<NAME>', 'shows instance configuration', acl_sys: :admin
124
+ describe 'config:set', '<NAME> <ENV_VARIABLE> <VALUE>', 'sets environment variable', acl_sys: :admin
125
+ describe 'config:unset', '<NAME> <ENV_VARIABLE>', 'unsets environment variable', acl_sys: :admin
126
+ describe 'config:set_from', '<NAME> <VALUE>', 'sets base image name for container', acl_sys: :admin
127
+ describe 'config:unset_from', '<NAME>', 'sets base image to default', acl_sys: :admin
128
+ describe 'config:set_engine', '<NAME> <ENGINE>', 'sets container engine (docker, lxc)', acl_sys: :admin
129
+ describe 'config:unset_engine', '<NAME>', 'sets engine to default', acl_sys: :admin
130
+
131
+ def dir(name)
132
+ File.join(Deployku::Config.home, '.postgres', Deployku.sanitize_app_name(name))
133
+ end
134
+
135
+ def container_name(app_name)
136
+ "deployku-postgres-#{app_name}"
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,100 @@
1
+ require 'fileutils'
2
+
3
+ module Deployku
4
+ class RailsPlugin < Deployku::Plugin
5
+ PACKAGES = ['nodejs']
6
+
7
+ def volumes
8
+ ['/app/public/']
9
+ end
10
+
11
+ def port
12
+ 3000
13
+ end
14
+
15
+ def build_start_script(path)
16
+ app_path = File.join(path, 'app')
17
+ start_path = File.join(path, 'start')
18
+ custom_start_path = File.join(app_path, 'start')
19
+ if File.exists?(custom_start_path)
20
+ FileUtils.cp(custom_start_path, start_path)
21
+ else
22
+ File.open(start_path, 'w') do |f|
23
+ f << <<EOF
24
+ #!/usr/bin/env bash
25
+ source /usr/local/rvm/scripts/rvm
26
+ cd app
27
+ export RAILS_ENV=production
28
+ bundle exec rake db:migrate RAILS_ENV=production
29
+ bundle exec rake assets:precompile RAILS_ENV=production
30
+
31
+ bundle exec rails s -p #{Deployku::Config.port} -b 0.0.0.0 -e production
32
+ EOF
33
+ end
34
+ end
35
+ File.chmod(0755, start_path)
36
+ end
37
+
38
+ def build_dockerfile(path)
39
+ app_path = File.join(path, 'app')
40
+ ruby_version = detect_ruby_version(app_path)
41
+ dockerfile_path = File.join(path, 'Dockerfile')
42
+ # TODO: process Dockerfile with erubis
43
+ custom_docker_file = File.join(app_path, 'Dockerfile')
44
+ if File.exists?(custom_docker_file)
45
+ FileUtils.cp(custom_docker_file, dockerfile_path)
46
+ else
47
+ File.open(dockerfile_path, 'w') do |f|
48
+ f << <<EOF
49
+ FROM #{Deployku::Config.from}
50
+
51
+ ENV DEBIAN_FRONTEND noninteractive
52
+
53
+ RUN apt-get update
54
+
55
+ RUN /bin/bash -l -c 'rvm install #{ruby_version} && rvm use #{ruby_version} --default'
56
+ RUN /bin/bash -l -c 'rvm rubygems current'
57
+ RUN /bin/bash -l -c 'gem install bundler'
58
+
59
+ RUN /bin/bash -l -c 'rvm cleanup all'
60
+
61
+ RUN apt-get install -y #{packages.join(' ')}
62
+
63
+ RUN apt-get -y autoclean
64
+ RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
65
+
66
+ EXPOSE #{Deployku::Config.port}
67
+ CMD []
68
+ ENTRYPOINT ["/start"]
69
+
70
+ ADD start /start
71
+
72
+ ADD app /app
73
+ RUN /bin/bash -l -c 'cd app && RAILS_ENV=production bundle install --without development test'
74
+ EOF
75
+ end
76
+ end
77
+ end
78
+
79
+ def detect(path)
80
+ gem_file_path = File.join(path, 'Gemfile')
81
+ if File.exists?(gem_file_path)
82
+ if File.read(gem_file_path) =~ %r{^\s*gem\s+['"](rails)['"]}m
83
+ return true
84
+ end
85
+ end
86
+ false
87
+ end
88
+
89
+ def detect_ruby_version(path)
90
+ gem_file_path = File.join(path, 'Gemfile')
91
+ if File.exists?(gem_file_path)
92
+ ruby_version = File.read(gem_file_path).gsub(%r{.*ruby\s+['"]([^'"]+)['"].*}m, '\1')
93
+ end
94
+ if not ruby_version || ruby_version == ''
95
+ ruby_version = '2.1.7'
96
+ end
97
+ ruby_version
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,111 @@
1
+ module Deployku
2
+
3
+ class Plugin
4
+ @plugins = []
5
+
6
+ class NoMethod < NoMethodError
7
+ end
8
+
9
+ class << self
10
+ attr_reader :plugins
11
+ end
12
+
13
+ def self.<<(plugin)
14
+ @plugins << plugin
15
+ end
16
+
17
+ def self.find_plugin(name)
18
+ plugin_name = "Deployku::#{name.capitalize}Plugin"
19
+ @plugins.each do |plugin|
20
+ return plugin if plugin.name == plugin_name
21
+ end
22
+ nil
23
+ end
24
+
25
+ def self.filter_plugins(fn)
26
+ plugins = []
27
+ @plugins.each do |plugin|
28
+ plug = plugin.instance
29
+ plugins << plug if plug.respond_to?(fn)
30
+ end
31
+ plugins
32
+ end
33
+
34
+ def self.inherited(plugin)
35
+ Plugin << plugin
36
+ plugin.instance_eval do
37
+ @help_register = []
38
+ class << self
39
+ attr_reader :help_register
40
+ end
41
+ def describe(fn_name, args, description, acl={})
42
+ @help_register << { name: fn_name, arg_list: args, desc: description, acl_app: acl[:acl_app], acl_sys: acl[:acl_sys] }
43
+ end
44
+ end
45
+ end
46
+
47
+ # collects info from 'describe' and returns it as a string
48
+ def self.help
49
+ str = ''
50
+ help_register = []
51
+ max_name_length = 0
52
+ max_arg_length = 0
53
+ max_desc_length = 0
54
+ @plugins.each do |plugin|
55
+ plugin.name =~ /Deployku::(.*?)Plugin/
56
+ next unless $1
57
+ name = $1.downcase
58
+ plugin.help_register.each do |reg|
59
+ new_reg = { name: "#{name}:#{reg[:name]}", args: reg[:arg_list], desc: reg[:desc] }
60
+ max_name_length = new_reg[:name].length if new_reg[:name].length > max_name_length
61
+ max_arg_length = new_reg[:args].length if new_reg[:args].length > max_arg_length
62
+ max_desc_length = new_reg[:desc].length if new_reg[:desc].length > max_desc_length
63
+ help_register << new_reg
64
+ end
65
+ end
66
+ help_register.each do |reg|
67
+ str << " %-#{max_name_length}s %-#{max_arg_length}s %s\n" % [reg[:name], reg[:args], reg[:desc]]
68
+ end
69
+ str
70
+ end
71
+
72
+ # run command in a plugin
73
+ def self.run(fn, args=[])
74
+ fn_name = fn.to_s.gsub(':', '_')
75
+ fn_desc = command_description(fn)
76
+ unless fn_desc
77
+ puts "Unknown command '#{fn}'."
78
+ exit 1
79
+ end
80
+ if fn_desc[:acl_app]
81
+ fn_desc[:acl_app].each do |idx, right|
82
+ Deployku::AccessPlugin.instance.check_app_rights(args[idx], right, true)
83
+ end
84
+ end
85
+ if fn_desc[:acl_sys]
86
+ Deployku::AccessPlugin.instance.check_system_rights(fn_desc[:acl_sys], true)
87
+ end
88
+ plug = instance
89
+ raise Deployku::Plugin::NoMethod.new("no method '#{plug.class.name}.#{fn}'") unless plug.respond_to?(fn_name)
90
+ plug.send(fn_name, *args)
91
+ end
92
+
93
+ def self.instance
94
+ @instance ||= self.new
95
+ end
96
+
97
+ def self.command_description(fn)
98
+ self.help_register.each do |reg|
99
+ return reg if reg[:name].to_s == fn.to_s
100
+ end
101
+ nil
102
+ end
103
+
104
+ # concatenate system wide packages and packages required by plugin
105
+ def packages
106
+ Deployku::Config.packages + self.class::PACKAGES
107
+ end
108
+
109
+ end
110
+
111
+ end
data/lib/deployku.rb ADDED
@@ -0,0 +1,19 @@
1
+ dir = File.expand_path(File.dirname(__FILE__))
2
+ $:.unshift(dir) unless $:.include?(dir)
3
+
4
+ require 'deployku/config'
5
+ require 'deployku/helpers'
6
+ require 'deployku/configurable'
7
+ require 'deployku/containerable'
8
+ require 'deployku/plugins'
9
+ require 'deployku/engine'
10
+
11
+ # load core plugins
12
+ require 'deployku/plugins/access'
13
+ require 'deployku/plugins/docker'
14
+ require 'deployku/plugins/lxc'
15
+ require 'deployku/plugins/app'
16
+ require 'deployku/plugins/git'
17
+ require 'deployku/plugins/postgres'
18
+ require 'deployku/plugins/rails'
19
+ require 'deployku/plugins/nginx'
metadata ADDED
@@ -0,0 +1,63 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: deployku
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Petr Kovář
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-11-09 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description:
14
+ email: pejuko@gmail.com
15
+ executables:
16
+ - deployku
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - LICENSE
21
+ - README.md
22
+ - Rakefile
23
+ - bin/deployku
24
+ - deployku.gemspec
25
+ - lib/deployku.rb
26
+ - lib/deployku/config.rb
27
+ - lib/deployku/configurable.rb
28
+ - lib/deployku/containerable.rb
29
+ - lib/deployku/engine.rb
30
+ - lib/deployku/helpers.rb
31
+ - lib/deployku/plugins.rb
32
+ - lib/deployku/plugins/access.rb
33
+ - lib/deployku/plugins/app.rb
34
+ - lib/deployku/plugins/docker.rb
35
+ - lib/deployku/plugins/git.rb
36
+ - lib/deployku/plugins/lxc.rb
37
+ - lib/deployku/plugins/nginx.rb
38
+ - lib/deployku/plugins/postgres.rb
39
+ - lib/deployku/plugins/rails.rb
40
+ homepage: http://github.com/deployku/deployku
41
+ licenses: []
42
+ metadata: {}
43
+ post_install_message:
44
+ rdoc_options: []
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: '0'
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: '0'
57
+ requirements: []
58
+ rubyforge_project:
59
+ rubygems_version: 2.4.8
60
+ signing_key:
61
+ specification_version: 4
62
+ summary: Deploy applications using git with zero down time
63
+ test_files: []