conjure 0.1.6 → 0.1.7
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 +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
|
-
|