conjure 0.1.6 → 0.1.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/History.md +5 -0
- data/lib/conjure.rb +5 -0
- data/lib/conjure/application.rb +32 -0
- data/lib/conjure/command.rb +23 -21
- data/lib/conjure/config.rb +1 -2
- data/lib/conjure/data_set.rb +7 -0
- data/lib/conjure/identity.rb +25 -0
- data/lib/conjure/instance.rb +7 -0
- data/lib/conjure/notes.txt +58 -0
- data/lib/conjure/provider.rb +26 -0
- data/lib/conjure/service/cloud_server.rb +25 -52
- data/lib/conjure/service/database.rb +2 -2
- data/lib/conjure/service/database/mysql.rb +2 -2
- data/lib/conjure/service/database/postgres.rb +2 -2
- data/lib/conjure/service/digital_ocean_account.rb +31 -0
- data/lib/conjure/service/docker_host.rb +0 -1
- data/lib/conjure/service/docker_shell.rb +2 -2
- data/lib/conjure/service/forwarded_shell.rb +1 -1
- data/lib/conjure/service/rails_codebase.rb +5 -10
- data/lib/conjure/service/rails_console.rb +10 -0
- data/lib/conjure/service/rails_deployment.rb +39 -0
- data/lib/conjure/service/rails_log_view.rb +14 -0
- data/lib/conjure/service/rails_server.rb +13 -36
- data/lib/conjure/service/rake_task.rb +11 -0
- data/lib/conjure/service/remote_file_set.rb +24 -0
- data/lib/conjure/service/remote_shell.rb +1 -0
- data/lib/conjure/service/repository_link.rb +2 -1
- data/lib/conjure/service/volume.rb +3 -3
- data/lib/conjure/target.rb +19 -0
- data/lib/conjure/version.rb +1 -1
- metadata +50 -50
- data/lib/conjure/service/rails_application.rb +0 -43
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 58a9a73a25cd4300e2bd4bdf5184a43c824ac548
|
4
|
+
data.tar.gz: 24a8eed9346681d7010d459d3e5de5a9bb106feb
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e0e0dadb4bab906cb2ef594d8827ba57f4c553daa09068646945952882dac1a03cdec41feb411a90d62ccef5504f6d7a358ebcd64176b283c646796ec015a670
|
7
|
+
data.tar.gz: 70e583f8ef4c570da0054ef44038c4028c372226bb962713d09cb14fafb0072344a9db066022bd7d2f061ffc6c038b8fe168e6d389456e1064809fc787c0e522
|
data/History.md
CHANGED
data/lib/conjure.rb
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
module Conjure
|
2
|
+
require File.join(File.dirname(__FILE__), "conjure/provider")
|
2
3
|
Dir[File.join(File.dirname(__FILE__), "conjure/**/*.rb")].each { |f| require f }
|
3
4
|
|
4
5
|
def self.config
|
5
6
|
@config ||= Config.load Dir.pwd
|
6
7
|
end
|
8
|
+
|
9
|
+
def self.identity
|
10
|
+
@identity ||= Identity.new(config)
|
11
|
+
end
|
7
12
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Conjure
|
2
|
+
class Application
|
3
|
+
attr_reader :origin_url, :name
|
4
|
+
|
5
|
+
def initialize(options = {})
|
6
|
+
@origin_url = options[:origin_url] || find_origin_url(options[:path])
|
7
|
+
@name = find_name(@origin_url) if @origin_url
|
8
|
+
end
|
9
|
+
|
10
|
+
def instances
|
11
|
+
Instance.find(:application => self)
|
12
|
+
end
|
13
|
+
|
14
|
+
def data_sets
|
15
|
+
DataSet.find(:application => self)
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def find_name(origin_url)
|
21
|
+
match = origin_url.match(/\/([^.]+)\.git$/)
|
22
|
+
match[1] if match
|
23
|
+
end
|
24
|
+
|
25
|
+
def find_origin_url(path)
|
26
|
+
return unless path
|
27
|
+
remote_info = `cd #{path}; git remote -v |grep origin`
|
28
|
+
match = remote_info.match(/(git@github.com[^ ]+)/)
|
29
|
+
match[1] if match
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/conjure/command.rb
CHANGED
@@ -2,8 +2,6 @@ require "thor"
|
|
2
2
|
|
3
3
|
module Conjure
|
4
4
|
class Command < Thor
|
5
|
-
attr_accessor :application_options
|
6
|
-
|
7
5
|
class_option :verbose, :aliases => "-v", :type => :boolean, :desc => "Show details of low-level operations for debugging"
|
8
6
|
def initialize(*args)
|
9
7
|
super
|
@@ -15,39 +13,41 @@ module Conjure
|
|
15
13
|
method_option :test, :type => :boolean, :desc => "Describe the deploy settings but don't deploy"
|
16
14
|
method_option :origin, :type => :string, :desc => "Specify git URL to deploy from"
|
17
15
|
def deploy
|
18
|
-
|
19
|
-
:branch => options[:branch],
|
20
|
-
:test => options[:test],
|
21
|
-
:origin => options[:origin],
|
22
|
-
}
|
23
|
-
application.deploy
|
16
|
+
deployment.deploy
|
24
17
|
end
|
25
18
|
|
26
19
|
desc "import FILE", "Import the production database from a postgres SQL dump"
|
27
20
|
def import(file)
|
28
|
-
|
21
|
+
deployment.database.import file
|
29
22
|
end
|
30
23
|
|
31
24
|
desc "export FILE", "Export the production database to a postgres SQL dump"
|
32
25
|
def export(file)
|
33
|
-
|
26
|
+
deployment.database.export file
|
34
27
|
end
|
35
28
|
|
36
29
|
desc "log", "Display the Rails log from the deployed application"
|
37
30
|
method_option :num, :aliases => "-n", :type => :numeric, :default => 10, :desc => "Show N lines of output"
|
38
31
|
method_option :tail, :aliases => "-t", :type => :boolean, :desc => "Continue streaming new log entries"
|
39
32
|
def log
|
40
|
-
|
33
|
+
Service::RailsLogView.new(:shell => deployment.shell, :lines => options[:num], :tail => options[:tail]) do |stdout|
|
34
|
+
print stdout
|
35
|
+
end
|
41
36
|
end
|
42
37
|
|
43
38
|
desc "rake [ARGUMENTS...]", "Run the specified rake task on the deployed application"
|
44
39
|
def rake(*arguments)
|
45
|
-
|
40
|
+
task = arguments.join(" ")
|
41
|
+
Service::RakeTask.new(:task => task, :shell => deployment.shell) do |stdout|
|
42
|
+
print stdout
|
43
|
+
end
|
46
44
|
end
|
47
45
|
|
48
46
|
desc "console", "Start a console on the deployed application"
|
49
47
|
def console
|
50
|
-
|
48
|
+
Service::RailsConsole.new(:shell => deployment.shell) do |stdout|
|
49
|
+
print stdout
|
50
|
+
end
|
51
51
|
end
|
52
52
|
|
53
53
|
default_task :help
|
@@ -55,18 +55,20 @@ module Conjure
|
|
55
55
|
private
|
56
56
|
|
57
57
|
def application
|
58
|
-
|
59
|
-
self.application_options[:origin] ||= github_url
|
60
|
-
Service::RailsApplication.new self.application_options
|
58
|
+
@application ||= Application.new(:path => Dir.pwd, :origin_url => options[:origin])
|
61
59
|
end
|
62
60
|
|
63
|
-
def
|
64
|
-
|
61
|
+
def deployment
|
62
|
+
@deployment ||= Service::RailsDeployment.new({
|
63
|
+
:branch => options[:branch],
|
64
|
+
:origin => application.origin_url,
|
65
|
+
:target => target,
|
66
|
+
:test => options[:test],
|
67
|
+
})
|
65
68
|
end
|
66
69
|
|
67
|
-
def
|
68
|
-
|
69
|
-
remote_info.match(/(git@github.com[^ ]+)/)[1]
|
70
|
+
def target
|
71
|
+
Target.new(:machine_name => "#{application.name}-production")
|
70
72
|
end
|
71
73
|
end
|
72
74
|
end
|
data/lib/conjure/config.rb
CHANGED
@@ -0,0 +1,25 @@
|
|
1
|
+
module Conjure
|
2
|
+
class Identity
|
3
|
+
require "digest/md5"
|
4
|
+
|
5
|
+
def initialize(config)
|
6
|
+
@config = config
|
7
|
+
end
|
8
|
+
|
9
|
+
def private_key_path
|
10
|
+
Pathname.new(@config.config_path).join @config.private_key_file
|
11
|
+
end
|
12
|
+
|
13
|
+
def public_key_path
|
14
|
+
Pathname.new(@config.config_path).join @config.public_key_file
|
15
|
+
end
|
16
|
+
|
17
|
+
def public_key_data
|
18
|
+
File.open(public_key_path, "rb") { |file| file.read }
|
19
|
+
end
|
20
|
+
|
21
|
+
def unique_identifier
|
22
|
+
"conjure_#{Digest::MD5.hexdigest(public_key_data)[0..7]}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
Application.deploy should become Deployment.create
|
2
|
+
|
3
|
+
Instead of passing DockerHost objects around, pass something that
|
4
|
+
knows how to provision OS shells (possibly from multiple sources).
|
5
|
+
DigitalOceanAccount etc should be an implementation of this interface.
|
6
|
+
shell = shell_source.prepare_shell do
|
7
|
+
run "cmd"
|
8
|
+
run "cmd2"
|
9
|
+
environment :key => "value"
|
10
|
+
port 80
|
11
|
+
end
|
12
|
+
|
13
|
+
Application - the code to be deployed (in the abstract, i.e. in a
|
14
|
+
repo not yet copied to the server(s)
|
15
|
+
|
16
|
+
Instance - a specific running copy of an application
|
17
|
+
accessed through various interfaces: web address, rails console, etc
|
18
|
+
|
19
|
+
Database - n/a, too ambiguous
|
20
|
+
Dataset - A specific data set
|
21
|
+
accessed through an interface w/ a specific db protocol.
|
22
|
+
|
23
|
+
Deployment should return a shell in the app environment as an
|
24
|
+
interface
|
25
|
+
|
26
|
+
Deployment should return a DataSet (that possible aggregates multiple
|
27
|
+
data sets used by the app). If an app needs a MySQL database, a Redis
|
28
|
+
database, and a local directory of user-uploaded files, all these must
|
29
|
+
stay in sync with each other and so should be aggregated under a
|
30
|
+
single DataSet interface.
|
31
|
+
|
32
|
+
Instance should instantiate and provide subsequent access to all
|
33
|
+
runtime dependencies of the codebase. This includes the web server,
|
34
|
+
data sets, etc. An app's mutable local filesystem should be considered
|
35
|
+
a data set too, and probably also the logs.
|
36
|
+
|
37
|
+
An Application should be something more abstract than the current
|
38
|
+
Codebase. It shouldn't know about the rails environment or the
|
39
|
+
database, it should be little more than a reference to a git repo. The
|
40
|
+
concept of a "codebase" that's checked out onto the deployment
|
41
|
+
server(s) should be something else (maybe just a Volume that a branch
|
42
|
+
of the application gets copied to).
|
43
|
+
|
44
|
+
But where do the database, logger, cron jobs, and other required
|
45
|
+
services get identified and instantiated?
|
46
|
+
|
47
|
+
Conjure's basic job is: deploy [something] [somewhere] using
|
48
|
+
[resources]. "Something" is a Service, of which Instance and DataSet
|
49
|
+
are both types. "Somewhere" is the desired interface over which the
|
50
|
+
new Service will be accessible. "Resource" is the cloud service, local
|
51
|
+
VMs, and other combined resources that will be used to do the
|
52
|
+
deployment.
|
53
|
+
|
54
|
+
Need a concept for something that has both stdin and stdout (and
|
55
|
+
stderr) streams ("Console"?). This is what's returned by a rake task
|
56
|
+
or rails console instantiation, to connect it to the user's console,
|
57
|
+
and it can also be returned from a CommandShell to give the user
|
58
|
+
direct access to that as well.
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Conjure
|
2
|
+
module Provider
|
3
|
+
def self.included(base)
|
4
|
+
base.extend ClassMethods
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.all(service_type)
|
8
|
+
providers(service_type).map{|block| block.call}.flatten.compact
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.register_provider(service_type, &block)
|
12
|
+
providers(service_type) << block
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.providers(service_type)
|
16
|
+
@providers ||= {}
|
17
|
+
@providers[service_type] ||= []
|
18
|
+
end
|
19
|
+
|
20
|
+
module ClassMethods
|
21
|
+
def provides(service_type, &block)
|
22
|
+
Conjure::Provider.register_provider(service_type, &block)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -2,7 +2,6 @@ module Conjure
|
|
2
2
|
module Service
|
3
3
|
class CloudServer
|
4
4
|
require "fog"
|
5
|
-
require "digest/md5"
|
6
5
|
require "pathname"
|
7
6
|
|
8
7
|
def initialize(name)
|
@@ -11,22 +10,13 @@ module Conjure
|
|
11
10
|
|
12
11
|
def run(command, options = {}, &block)
|
13
12
|
set_fog_credentials
|
14
|
-
|
13
|
+
file_set = RemoteFileSet.new(:shell => remote_shell, :files => options[:files])
|
14
|
+
file_set.upload
|
15
15
|
result = remote_shell.run(command, :stream_stdin => options[:stream_stdin], &block)
|
16
|
-
|
16
|
+
file_set.remove
|
17
17
|
result
|
18
18
|
end
|
19
19
|
|
20
|
-
def upload_files(files)
|
21
|
-
dir_names = files.map{|local_path, remote_path| File.dirname remote_path}.uniq
|
22
|
-
run "mkdir -p #{dir_names.join ' '}" if dir_names.any?
|
23
|
-
files.each{|local_path, remote_path| server.scp local_path, remote_path}
|
24
|
-
end
|
25
|
-
|
26
|
-
def remove_files(files)
|
27
|
-
files.each{|local_path, remote_path| run "rm -f #{remote_path}"}
|
28
|
-
end
|
29
|
-
|
30
20
|
def server
|
31
21
|
@server ||= existing_server
|
32
22
|
@server ||= new_server
|
@@ -46,66 +36,49 @@ module Conjure
|
|
46
36
|
|
47
37
|
def new_server
|
48
38
|
Log.info " [cloud] Launching new server #{@name}"
|
49
|
-
|
39
|
+
bootstrap_options = account.bootstrap_options.merge(:name => @name)
|
40
|
+
options = prepare_bootstrap_options(bootstrap_options).merge(fog_credentials)
|
41
|
+
connection.servers.bootstrap options
|
50
42
|
end
|
51
43
|
|
52
|
-
def
|
53
|
-
@
|
54
|
-
end
|
55
|
-
|
56
|
-
def bootstrap_options
|
57
|
-
{
|
58
|
-
name: @name,
|
59
|
-
flavor_id: flavor_id,
|
60
|
-
region_id: region_id,
|
61
|
-
image_id: image_id,
|
62
|
-
}
|
44
|
+
def account
|
45
|
+
@account ||= Provider.all(:cloud_account).first
|
63
46
|
end
|
64
47
|
|
65
|
-
def
|
66
|
-
|
67
|
-
provider: :digitalocean,
|
68
|
-
digitalocean_api_key: Conjure.config.digitalocean_api_key,
|
69
|
-
digitalocean_client_id: Conjure.config.digitalocean_client_id,
|
70
|
-
}
|
48
|
+
def connection
|
49
|
+
@connection ||= Fog::Compute.new account.compute_options
|
71
50
|
end
|
72
51
|
|
73
|
-
def
|
74
|
-
|
52
|
+
def add_resource_id(options, type)
|
53
|
+
id = "#{type}_id".to_sym
|
54
|
+
name = "#{type}_name".to_sym
|
55
|
+
collection = "#{type}s".to_sym
|
56
|
+
options[id] = resource_id(collection, options[name]) if options[name]
|
75
57
|
end
|
76
58
|
|
77
|
-
def
|
78
|
-
|
59
|
+
def prepare_bootstrap_options(options)
|
60
|
+
add_resource_id(options, :flavor)
|
61
|
+
add_resource_id(options, :region)
|
62
|
+
add_resource_id(options, :image)
|
63
|
+
options
|
79
64
|
end
|
80
65
|
|
81
|
-
def
|
82
|
-
|
66
|
+
def resource_id(collection, name)
|
67
|
+
connection.send(collection).find{|i| i.name == name}.id
|
83
68
|
end
|
84
69
|
|
85
70
|
def set_fog_credentials
|
86
|
-
Fog.credential =
|
71
|
+
Fog.credential = Conjure.identity.unique_identifier
|
87
72
|
Fog.credentials.merge! fog_credentials
|
88
73
|
end
|
89
74
|
|
90
|
-
def private_key_file
|
91
|
-
Pathname.new(Conjure.config.config_path).join Conjure.config.private_key_file
|
92
|
-
end
|
93
|
-
|
94
|
-
def public_key_file
|
95
|
-
Pathname.new(Conjure.config.config_path).join Conjure.config.public_key_file
|
96
|
-
end
|
97
|
-
|
98
75
|
def fog_credentials
|
99
76
|
{
|
100
|
-
private_key_path:
|
101
|
-
public_key_path:
|
77
|
+
private_key_path: Conjure.identity.private_key_path,
|
78
|
+
public_key_path: Conjure.identity.public_key_path,
|
102
79
|
}
|
103
80
|
end
|
104
81
|
|
105
|
-
def fog_key_identifier
|
106
|
-
"conjure_#{Digest::MD5.hexdigest(File.read public_key_file)[0..7]}"
|
107
|
-
end
|
108
|
-
|
109
82
|
def remote_shell
|
110
83
|
@remote_shell ||= RemoteShell.new(
|
111
84
|
:ip_address => server.public_ip_address,
|
@@ -5,8 +5,8 @@ module Conjure
|
|
5
5
|
services_by_gem.each do |gem_name, service_class|
|
6
6
|
if options[:codebase].gem_names.include? gem_name
|
7
7
|
return service_class.new(
|
8
|
-
:
|
9
|
-
:database_name =>
|
8
|
+
:target => options[:target],
|
9
|
+
:database_name => "rails_app_db",
|
10
10
|
:adapter_name => adapters_by_gem[gem_name],
|
11
11
|
)
|
12
12
|
end
|
@@ -3,13 +3,13 @@ module Conjure
|
|
3
3
|
class Database
|
4
4
|
class Mysql
|
5
5
|
def initialize(options)
|
6
|
-
@
|
6
|
+
@target = options[:target]
|
7
7
|
@db_name = options[:database_name]
|
8
8
|
@adapter_name = options[:adapter_name]
|
9
9
|
end
|
10
10
|
|
11
11
|
def base_image
|
12
|
-
@base_image ||= @
|
12
|
+
@base_image ||= @target.shell.prepare(
|
13
13
|
label: "mysql",
|
14
14
|
setup_commands: [
|
15
15
|
"apt-get install -y mysql-server mysql-client"
|
@@ -3,12 +3,12 @@ module Conjure
|
|
3
3
|
class Database
|
4
4
|
class Postgres
|
5
5
|
def initialize(options)
|
6
|
-
@
|
6
|
+
@target = options[:target]
|
7
7
|
@db_name = options[:database_name]
|
8
8
|
end
|
9
9
|
|
10
10
|
def base_image
|
11
|
-
@base_image ||= @
|
11
|
+
@base_image ||= @target.shell.prepare(
|
12
12
|
label: "postgres",
|
13
13
|
setup_commands: [
|
14
14
|
"apt-get install -y python-software-properties software-properties-common",
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Conjure
|
2
|
+
module Service
|
3
|
+
class DigitalOceanAccount
|
4
|
+
include Conjure::Provider
|
5
|
+
|
6
|
+
provides :cloud_account do
|
7
|
+
new if configured?
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.configured?
|
11
|
+
Conjure.config.digitalocean_api_key and Conjure.config.digitalocean_client_id
|
12
|
+
end
|
13
|
+
|
14
|
+
def compute_options
|
15
|
+
{
|
16
|
+
:provider => :digitalocean,
|
17
|
+
:digitalocean_api_key => Conjure.config.digitalocean_api_key,
|
18
|
+
:digitalocean_client_id => Conjure.config.digitalocean_client_id,
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
def bootstrap_options
|
23
|
+
{
|
24
|
+
:flavor_name => "512MB",
|
25
|
+
:region_name => (Conjure.config.digitalocean_region || "New York 1"),
|
26
|
+
:image_name => "Ubuntu 13.04 x64",
|
27
|
+
}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -43,7 +43,6 @@ module Conjure
|
|
43
43
|
full_command = "nohup #{full_command}" if options[:nohup]
|
44
44
|
full_command = "echo '#{shell_escape options[:stdin]}' | #{full_command}" if options[:stdin]
|
45
45
|
Log.debug " [scp] #{options[:files].inspect}" if options[:files]
|
46
|
-
Log.debug " [ssh] #{full_command}"
|
47
46
|
result = server.run full_command, :stream_stdin => options[:stream_stdin], :files => options[:files], &block
|
48
47
|
raise "Docker error: #{result.stdout} #{result.stderr}" unless result.status == 0
|
49
48
|
result.stdout
|
@@ -16,7 +16,7 @@ module Conjure
|
|
16
16
|
def command(c)
|
17
17
|
container = @shell.run "/usr/sbin/sshd -D -e"
|
18
18
|
escaped_command = @shell.docker_host.shell_escape c
|
19
|
-
ssh_command = "ssh -A -o StrictHostKeyChecking=no #{container.ip_address} '#{escaped_command}'"
|
19
|
+
ssh_command = "ssh -A -o StrictHostKeyChecking=no -o PasswordAuthentication=no #{container.ip_address} '#{escaped_command}'"
|
20
20
|
result = @shell.docker_host.server.run ssh_command
|
21
21
|
result.stdout
|
22
22
|
end
|
@@ -1,12 +1,11 @@
|
|
1
1
|
module Conjure
|
2
2
|
module Service
|
3
3
|
class RailsCodebase
|
4
|
-
def initialize(
|
4
|
+
def initialize(target, github_url, branch, rails_environment)
|
5
5
|
@github_url = github_url
|
6
6
|
@branch = branch
|
7
|
-
@app_name = app_name
|
8
7
|
@rails_environment = rails_environment
|
9
|
-
@
|
8
|
+
@target = target
|
10
9
|
end
|
11
10
|
|
12
11
|
def database_yml
|
@@ -33,12 +32,12 @@ module Conjure
|
|
33
32
|
:volume => volume,
|
34
33
|
:branch => @branch,
|
35
34
|
:origin_url => @github_url,
|
36
|
-
:public_key => Conjure.
|
35
|
+
:public_key => Conjure.identity.public_key_data.gsub("\n", "\\n"),
|
37
36
|
)
|
38
37
|
end
|
39
38
|
|
40
39
|
def volume
|
41
|
-
@volume ||= Volume.new(:
|
40
|
+
@volume ||= Volume.new(:target => @target, :host_path => "/rails_app", :container_path => "/application_root")
|
42
41
|
end
|
43
42
|
|
44
43
|
def configure_database
|
@@ -52,16 +51,12 @@ module Conjure
|
|
52
51
|
volume.write "config/initializers/z_conjure_logger.rb", setup
|
53
52
|
end
|
54
53
|
|
55
|
-
def database_name
|
56
|
-
"#{@app_name}_#{@rails_environment}"
|
57
|
-
end
|
58
|
-
|
59
54
|
def gem_names
|
60
55
|
volume.read("Gemfile").scan(/gem ['"]([^'"]+)['"]/).flatten
|
61
56
|
end
|
62
57
|
|
63
58
|
def database
|
64
|
-
@database ||= Database.new :
|
59
|
+
@database ||= Database.new :target => @target, :codebase => self
|
65
60
|
end
|
66
61
|
end
|
67
62
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Conjure
|
2
|
+
module Service
|
3
|
+
class RailsDeployment
|
4
|
+
def initialize(options)
|
5
|
+
@origin = options[:origin]
|
6
|
+
@branch = options[:branch] || "master"
|
7
|
+
@environment = "production"
|
8
|
+
@test = options[:test]
|
9
|
+
@target = options[:target]
|
10
|
+
end
|
11
|
+
|
12
|
+
def deploy
|
13
|
+
Log.info "[deploy] Deploying #{@branch} to #{@environment}"
|
14
|
+
unless @test
|
15
|
+
codebase.install
|
16
|
+
rails.run
|
17
|
+
Log.info "[deploy] Application deployed to #{@target.ip_address}"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def database
|
22
|
+
codebase.database
|
23
|
+
end
|
24
|
+
|
25
|
+
def codebase
|
26
|
+
@codebase ||= Service::RailsCodebase.new @target, @origin, @branch, @environment
|
27
|
+
end
|
28
|
+
|
29
|
+
def rails
|
30
|
+
@rails ||= Service::RailsServer.new @target, @environment
|
31
|
+
end
|
32
|
+
|
33
|
+
def shell
|
34
|
+
rails.base_image
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Conjure
|
2
|
+
module Service
|
3
|
+
class RailsLogView
|
4
|
+
def initialize(options, &block)
|
5
|
+
arguments = []
|
6
|
+
arguments << "-n #{options[:lines]}" if options[:lines]
|
7
|
+
arguments << "-f" if options[:tail]
|
8
|
+
arguments << "application_root/log/production.log"
|
9
|
+
options[:shell].command("tail #{arguments.join ' '}", &block)
|
10
|
+
rescue Interrupt
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -1,19 +1,19 @@
|
|
1
1
|
module Conjure
|
2
2
|
module Service
|
3
3
|
class RailsServer
|
4
|
-
def initialize(
|
5
|
-
@
|
6
|
-
@app_name = app_name
|
4
|
+
def initialize(target, rails_environment)
|
5
|
+
@target = target
|
7
6
|
@rails_environment = rails_environment
|
8
7
|
end
|
9
8
|
|
10
9
|
def base_image
|
11
|
-
@base_image ||= @
|
10
|
+
@base_image ||= @target.shell.prepare(
|
12
11
|
label: "rails_base",
|
13
12
|
setup_commands: [
|
14
13
|
"apt-get install -y curl git",
|
15
14
|
"curl -L https://get.rvm.io | bash -s stable",
|
16
|
-
"rvm install #{ruby_version}",
|
15
|
+
"/usr/local/rvm/bin/rvm install #{ruby_version}",
|
16
|
+
"ln -s /usr/local/rvm/rubies/* /usr/local/rvm/default-ruby",
|
17
17
|
"bash -c 'source /usr/local/rvm/scripts/rvm; rvm use #{ruby_version}@global --default'",
|
18
18
|
"ln -s /usr/local/rvm/rubies/*/lib/ruby/gems/* /usr/local/rvm/gems/default",
|
19
19
|
"apt-get install -y #{apt_packages_required_for_gems.join ' '}",
|
@@ -25,12 +25,12 @@ module Conjure
|
|
25
25
|
|
26
26
|
],
|
27
27
|
environment: {
|
28
|
-
PATH:"/usr/local/rvm/gems/default/bin:/usr/local/rvm/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
|
28
|
+
PATH:"/usr/local/rvm/gems/default/bin:/usr/local/rvm/default-ruby/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
|
29
29
|
RAILS_ENV: @rails_environment,
|
30
30
|
GITHUB_TOKEN: ENV["GITHUB_TOKEN"],
|
31
31
|
FRECKLE_SUBDOMAIN: "neomind",
|
32
32
|
},
|
33
|
-
host_volumes: {"/rails_app" => "
|
33
|
+
host_volumes: {"/rails_app" => "/application_root"},
|
34
34
|
)
|
35
35
|
end
|
36
36
|
|
@@ -39,7 +39,7 @@ module Conjure
|
|
39
39
|
label: "rails_server",
|
40
40
|
ports: [80],
|
41
41
|
environment: {
|
42
|
-
PATH:"/usr/local/rvm/gems/default/bin:/usr/local/rvm/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
|
42
|
+
PATH:"/usr/local/rvm/gems/default/bin:/usr/local/rvm/default-ruby/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
|
43
43
|
},
|
44
44
|
)
|
45
45
|
end
|
@@ -52,7 +52,7 @@ module Conjure
|
|
52
52
|
|
53
53
|
def install_gems
|
54
54
|
Log.info "[ rails] Installing gems"
|
55
|
-
base_image.command "cd
|
55
|
+
base_image.command "cd application_root; bundle --deployment"
|
56
56
|
end
|
57
57
|
|
58
58
|
def update_database
|
@@ -61,45 +61,22 @@ module Conjure
|
|
61
61
|
|
62
62
|
def database_exists
|
63
63
|
Log.info "[ rails] Checking the database status"
|
64
|
-
base_image.command("cd
|
64
|
+
base_image.command("cd application_root; bundle exec rake db:version; true").include? "Current version:"
|
65
65
|
end
|
66
66
|
|
67
67
|
def migrate_database
|
68
68
|
Log.info "[ rails] Migrating the database"
|
69
|
-
base_image.command "cd
|
69
|
+
base_image.command "cd application_root; bundle exec rake db:migrate"
|
70
70
|
end
|
71
71
|
|
72
72
|
def initialize_database
|
73
73
|
Log.info "[ rails] Setting up the database"
|
74
|
-
base_image.command "cd
|
74
|
+
base_image.command "cd application_root; bundle exec rake db:setup"
|
75
75
|
end
|
76
76
|
|
77
77
|
def restart_server
|
78
78
|
server_image.stop
|
79
|
-
server_image.run "cd
|
80
|
-
end
|
81
|
-
|
82
|
-
def log(options = {})
|
83
|
-
arguments = []
|
84
|
-
arguments << "-n #{options[:lines]}" if options[:lines]
|
85
|
-
arguments << "-f" if options[:tail]
|
86
|
-
log_file = "#{@app_name}/log/#{@rails_environment}.log"
|
87
|
-
base_image.command "tail #{arguments.join ' '} #{log_file}" do |stdout, stderr|
|
88
|
-
puts stdout
|
89
|
-
end
|
90
|
-
rescue Interrupt => e
|
91
|
-
end
|
92
|
-
|
93
|
-
def rake(command)
|
94
|
-
base_image.command "cd #{@app_name}; bundle exec rake #{command}" do |stdout, stderr|
|
95
|
-
print stdout
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
def console
|
100
|
-
base_image.command "cd #{@app_name}; bundle exec rails console", :stream_stdin => true do |stdout, stderr|
|
101
|
-
print stdout
|
102
|
-
end
|
79
|
+
server_image.run "cd application_root; rm -f tmp/pids/server.pid; bundle exec rails server -p 80"
|
103
80
|
end
|
104
81
|
|
105
82
|
def ruby_version
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Conjure
|
2
|
+
module Service
|
3
|
+
class RemoteFileSet
|
4
|
+
require "net/scp"
|
5
|
+
|
6
|
+
def initialize(options)
|
7
|
+
@shell = options[:shell]
|
8
|
+
@files = options[:files].to_a
|
9
|
+
end
|
10
|
+
|
11
|
+
def upload
|
12
|
+
dir_names = @files.map{|local_path, remote_path| File.dirname remote_path}.uniq
|
13
|
+
@shell.run "mkdir -p #{dir_names.join ' '}" if dir_names.any?
|
14
|
+
@files.each do |local_path, remote_path|
|
15
|
+
@shell.session.scp.upload! local_path, remote_path
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def remove
|
20
|
+
@files.each{|local_path, remote_path| @shell.run "rm -f #{remote_path}"}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -20,7 +20,8 @@ module Conjure
|
|
20
20
|
|
21
21
|
def checkout_code
|
22
22
|
Log.info "[ repo] Checking out code from git"
|
23
|
-
git_shell.command "git clone -b #{@branch} #{@origin_url} #{code_path}"
|
23
|
+
output = git_shell.command "git clone -b #{@branch} #{@origin_url} #{code_path}"
|
24
|
+
raise "Access denied to git repo" if output.include? "Permission denied"
|
24
25
|
end
|
25
26
|
|
26
27
|
def fetch_code_updates
|
@@ -1,10 +1,10 @@
|
|
1
1
|
module Conjure
|
2
2
|
module Service
|
3
3
|
class Volume
|
4
|
-
attr_reader :
|
4
|
+
attr_reader :target, :container_path
|
5
5
|
|
6
6
|
def initialize(options)
|
7
|
-
@
|
7
|
+
@target = options[:target]
|
8
8
|
@host_path = options[:host_path]
|
9
9
|
@container_path = options[:container_path]
|
10
10
|
end
|
@@ -18,7 +18,7 @@ module Conjure
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def shell
|
21
|
-
@shell ||= @
|
21
|
+
@shell ||= @target.shell.prepare(
|
22
22
|
:label => "volume",
|
23
23
|
:host_volumes => {@host_path => @container_path},
|
24
24
|
)
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Conjure
|
2
|
+
class Target
|
3
|
+
def initialize(options)
|
4
|
+
@machine_name = options[:machine_name]
|
5
|
+
end
|
6
|
+
|
7
|
+
def shell
|
8
|
+
docker_host.shell
|
9
|
+
end
|
10
|
+
|
11
|
+
def ip_address
|
12
|
+
docker_host.ip_address
|
13
|
+
end
|
14
|
+
|
15
|
+
def docker_host
|
16
|
+
@docker_host ||= Service::DockerHost.new @machine_name
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/conjure/version.rb
CHANGED
metadata
CHANGED
@@ -1,94 +1,83 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: conjure
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
5
|
-
prerelease:
|
4
|
+
version: 0.1.7
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Brian Auton
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2014-01-14 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: fog
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
|
-
- -
|
17
|
+
- - ">="
|
20
18
|
- !ruby/object:Gem::Version
|
21
|
-
version: 1.
|
19
|
+
version: 1.19.0
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
|
-
- -
|
24
|
+
- - ">="
|
28
25
|
- !ruby/object:Gem::Version
|
29
|
-
version: 1.
|
26
|
+
version: 1.19.0
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: thor
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
|
-
- -
|
31
|
+
- - ">="
|
36
32
|
- !ruby/object:Gem::Version
|
37
33
|
version: '0'
|
38
34
|
type: :runtime
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
|
-
- -
|
38
|
+
- - ">="
|
44
39
|
- !ruby/object:Gem::Version
|
45
40
|
version: '0'
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
42
|
name: unf
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
44
|
requirements:
|
51
|
-
- -
|
45
|
+
- - ">="
|
52
46
|
- !ruby/object:Gem::Version
|
53
47
|
version: '0'
|
54
48
|
type: :runtime
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
51
|
requirements:
|
59
|
-
- -
|
52
|
+
- - ">="
|
60
53
|
- !ruby/object:Gem::Version
|
61
54
|
version: '0'
|
62
55
|
- !ruby/object:Gem::Dependency
|
63
|
-
name:
|
56
|
+
name: rspec
|
64
57
|
requirement: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
58
|
requirements:
|
67
|
-
- -
|
59
|
+
- - ">="
|
68
60
|
- !ruby/object:Gem::Version
|
69
|
-
version:
|
61
|
+
version: 3.0.0.beta1
|
70
62
|
type: :development
|
71
63
|
prerelease: false
|
72
64
|
version_requirements: !ruby/object:Gem::Requirement
|
73
|
-
none: false
|
74
65
|
requirements:
|
75
|
-
- -
|
66
|
+
- - ">="
|
76
67
|
- !ruby/object:Gem::Version
|
77
|
-
version:
|
68
|
+
version: 3.0.0.beta1
|
78
69
|
- !ruby/object:Gem::Dependency
|
79
70
|
name: rake
|
80
71
|
requirement: !ruby/object:Gem::Requirement
|
81
|
-
none: false
|
82
72
|
requirements:
|
83
|
-
- -
|
73
|
+
- - ">="
|
84
74
|
- !ruby/object:Gem::Version
|
85
75
|
version: '0'
|
86
76
|
type: :development
|
87
77
|
prerelease: false
|
88
78
|
version_requirements: !ruby/object:Gem::Requirement
|
89
|
-
none: false
|
90
79
|
requirements:
|
91
|
-
- -
|
80
|
+
- - ">="
|
92
81
|
- !ruby/object:Gem::Version
|
93
82
|
version: '0'
|
94
83
|
description:
|
@@ -99,51 +88,62 @@ executables:
|
|
99
88
|
extensions: []
|
100
89
|
extra_rdoc_files: []
|
101
90
|
files:
|
91
|
+
- History.md
|
92
|
+
- License.txt
|
93
|
+
- README.md
|
94
|
+
- bin/conjure
|
102
95
|
- lib/conjure.rb
|
96
|
+
- lib/conjure/application.rb
|
97
|
+
- lib/conjure/command.rb
|
98
|
+
- lib/conjure/config.rb
|
99
|
+
- lib/conjure/data_set.rb
|
100
|
+
- lib/conjure/identity.rb
|
101
|
+
- lib/conjure/instance.rb
|
102
|
+
- lib/conjure/log.rb
|
103
|
+
- lib/conjure/notes.txt
|
104
|
+
- lib/conjure/provider.rb
|
103
105
|
- lib/conjure/service/cloud_server.rb
|
104
|
-
- lib/conjure/service/
|
105
|
-
- lib/conjure/service/rails_codebase.rb
|
106
|
-
- lib/conjure/service/rails_application.rb
|
107
|
-
- lib/conjure/service/forwarded_shell.rb
|
108
|
-
- lib/conjure/service/repository_link.rb
|
109
|
-
- lib/conjure/service/volume.rb
|
110
|
-
- lib/conjure/service/database/postgres.rb
|
106
|
+
- lib/conjure/service/database.rb
|
111
107
|
- lib/conjure/service/database/mysql.rb
|
112
|
-
- lib/conjure/service/
|
108
|
+
- lib/conjure/service/database/postgres.rb
|
109
|
+
- lib/conjure/service/digital_ocean_account.rb
|
113
110
|
- lib/conjure/service/docker_host.rb
|
114
111
|
- lib/conjure/service/docker_shell.rb
|
115
|
-
- lib/conjure/service/
|
116
|
-
- lib/conjure/
|
117
|
-
- lib/conjure/
|
112
|
+
- lib/conjure/service/forwarded_shell.rb
|
113
|
+
- lib/conjure/service/rails_codebase.rb
|
114
|
+
- lib/conjure/service/rails_console.rb
|
115
|
+
- lib/conjure/service/rails_deployment.rb
|
116
|
+
- lib/conjure/service/rails_log_view.rb
|
117
|
+
- lib/conjure/service/rails_server.rb
|
118
|
+
- lib/conjure/service/rake_task.rb
|
119
|
+
- lib/conjure/service/remote_file_set.rb
|
120
|
+
- lib/conjure/service/remote_shell.rb
|
121
|
+
- lib/conjure/service/repository_link.rb
|
122
|
+
- lib/conjure/service/volume.rb
|
123
|
+
- lib/conjure/target.rb
|
118
124
|
- lib/conjure/version.rb
|
119
|
-
- lib/conjure/command.rb
|
120
|
-
- README.md
|
121
|
-
- History.md
|
122
|
-
- License.txt
|
123
|
-
- bin/conjure
|
124
125
|
homepage: http://github.com/brianauton/conjure
|
125
126
|
licenses:
|
126
127
|
- MIT
|
128
|
+
metadata: {}
|
127
129
|
post_install_message:
|
128
130
|
rdoc_options: []
|
129
131
|
require_paths:
|
130
132
|
- lib
|
131
133
|
required_ruby_version: !ruby/object:Gem::Requirement
|
132
|
-
none: false
|
133
134
|
requirements:
|
134
|
-
- -
|
135
|
+
- - ">="
|
135
136
|
- !ruby/object:Gem::Version
|
136
137
|
version: '0'
|
137
138
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
138
|
-
none: false
|
139
139
|
requirements:
|
140
|
-
- -
|
140
|
+
- - ">="
|
141
141
|
- !ruby/object:Gem::Version
|
142
142
|
version: 1.3.6
|
143
143
|
requirements: []
|
144
144
|
rubyforge_project:
|
145
|
-
rubygems_version:
|
145
|
+
rubygems_version: 2.2.1
|
146
146
|
signing_key:
|
147
|
-
specification_version:
|
147
|
+
specification_version: 4
|
148
148
|
summary: Magically powerful deployment for Rails applications
|
149
149
|
test_files: []
|
@@ -1,43 +0,0 @@
|
|
1
|
-
module Conjure
|
2
|
-
module Service
|
3
|
-
class RailsApplication
|
4
|
-
def initialize(options)
|
5
|
-
@origin = options[:origin]
|
6
|
-
@name = name_from_origin @origin
|
7
|
-
@branch = options[:branch] || "master"
|
8
|
-
@environment = "production"
|
9
|
-
@test = options[:test]
|
10
|
-
end
|
11
|
-
|
12
|
-
def deploy
|
13
|
-
Log.info "[deploy] Deploying #{@name}:#{@branch} to #{@environment}"
|
14
|
-
unless @test
|
15
|
-
codebase.install
|
16
|
-
rails.run
|
17
|
-
Log.info "[deploy] Application deployed to #{docker.ip_address}"
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
def docker
|
22
|
-
@docker ||= Service::DockerHost.new "#{@name}-#{@environment}"
|
23
|
-
end
|
24
|
-
|
25
|
-
def database
|
26
|
-
codebase.database
|
27
|
-
end
|
28
|
-
|
29
|
-
def codebase
|
30
|
-
@codebase ||= Service::RailsCodebase.new docker, @origin, @branch, @name, @environment
|
31
|
-
end
|
32
|
-
|
33
|
-
def rails
|
34
|
-
@rails ||= Service::RailsServer.new docker, @name, @environment
|
35
|
-
end
|
36
|
-
|
37
|
-
def name_from_origin(origin)
|
38
|
-
origin.match(/\/([^.]+)\.git$/)[1]
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|