deployku 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []