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 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
@@ -1,3 +1,8 @@
1
+ ### Version 0.1.7
2
+ 2014-1-14
3
+
4
+ * Improvements to error handling and verbose output
5
+
1
6
  ### Version 0.1.6
2
7
  2013-11-27
3
8
 
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
@@ -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
- self.application_options = {
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
- application.database.import file
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
- application.database.export file
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
- application.rails.log :lines => options[:num], :tail => options[:tail]
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
- application.rails.rake arguments.join(" ")
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
- application.rails.console
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
- self.application_options ||= {}
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 github_url
64
- git_origin_url Dir.pwd
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 git_origin_url(source_path)
68
- remote_info = `cd #{source_path}; git remote -v |grep origin`
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
@@ -14,8 +14,7 @@ module Conjure
14
14
  end
15
15
 
16
16
  def method_missing(name)
17
- return @options[name.to_s] if @options.has_key? name.to_s
18
- super
17
+ @options[name.to_s]
19
18
  end
20
19
 
21
20
  def file_contents(name)
@@ -0,0 +1,7 @@
1
+ module Conjure
2
+ class DataSet
3
+ def self.find(options = {})
4
+ []
5
+ end
6
+ end
7
+ end
@@ -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,7 @@
1
+ module Conjure
2
+ class Instance
3
+ def self.find(options = {})
4
+ []
5
+ end
6
+ end
7
+ 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
- upload_files options[:files].to_a
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
- remove_files options[:files].to_a
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
- connection.servers.bootstrap bootstrap_options.merge(fog_credentials)
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 connection
53
- @connection ||= Fog::Compute.new compute_options
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 compute_options
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 flavor_id
74
- @flavor_id ||= connection.flavors.find{|f| f.name == "512MB"}.id
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 region_id
78
- @region_id ||= connection.regions.find{|r| r.name == Conjure.config.digitalocean_region}.id
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 image_id
82
- @image_id ||= connection.images.find{|r| r.name == "Ubuntu 13.04 x64"}.id
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 = fog_key_identifier
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: private_key_file,
101
- public_key_path: public_key_file,
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
- :docker_host => options[:docker_host],
9
- :database_name => options[:codebase].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
- @host = options[:docker_host]
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 ||= @host.shell.prepare(
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
- @host = options[:docker_host]
6
+ @target = options[:target]
7
7
  @db_name = options[:database_name]
8
8
  end
9
9
 
10
10
  def base_image
11
- @base_image ||= @host.shell.prepare(
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
@@ -15,8 +15,8 @@ module Conjure
15
15
  )
16
16
  end
17
17
 
18
- def command(*args)
19
- (@image || default_image).command *args
18
+ def command(*args, &block)
19
+ (@image || default_image).command *args, &block
20
20
  end
21
21
 
22
22
  def run(*args)
@@ -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(host, github_url, branch, app_name, rails_environment)
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
- @host = host
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.config.file_contents(:public_key_file).gsub("\n", "\\n"),
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(:docker_host => @host, :host_path => "/rails_app", :container_path => "/#{@app_name}")
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 :docker_host => @host, :codebase => self
59
+ @database ||= Database.new :target => @target, :codebase => self
65
60
  end
66
61
  end
67
62
  end
@@ -0,0 +1,10 @@
1
+ module Conjure
2
+ module Service
3
+ class RailsConsole
4
+ def initialize(options, &block)
5
+ shell = options[:shell]
6
+ shell.command("cd application_root; bundle exec rails console", :stream_stdin => true, &block)
7
+ end
8
+ end
9
+ end
10
+ 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(host, app_name, rails_environment)
5
- @host = host
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 ||= @host.shell.prepare(
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" => "/#{@app_name}"},
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 #{@app_name}; bundle --deployment"
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 #{@app_name}; bundle exec rake db:version; true").include? "Current version:"
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 #{@app_name}; bundle exec rake db:migrate"
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 #{@app_name}; bundle exec rake db:setup"
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 #{@app_name}; rm -f tmp/pids/server.pid; bundle exec rails server -p 80"
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,11 @@
1
+ module Conjure
2
+ module Service
3
+ class RakeTask
4
+ def initialize(options, &block)
5
+ task = options[:task]
6
+ shell = options[:shell]
7
+ shell.command("cd application_root; bundle exec rake #{task}", &block)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -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
@@ -13,6 +13,7 @@ module Conjure
13
13
  end
14
14
 
15
15
  def run(command, options = {}, &block)
16
+ Log.debug " [ssh] #{command}"
16
17
  result = nil
17
18
  session.open_channel do |channel|
18
19
  channel.request_pty
@@ -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 :docker_host, :container_path
4
+ attr_reader :target, :container_path
5
5
 
6
6
  def initialize(options)
7
- @docker_host = options[:docker_host]
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 ||= @docker_host.shell.prepare(
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
@@ -1,3 +1,3 @@
1
1
  module Conjure
2
- VERSION = "0.1.6" unless defined?(VERSION)
2
+ VERSION = "0.1.7" unless defined?(VERSION)
3
3
  end
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.6
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: 2013-11-28 00:00:00.000000000 Z
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.15.0
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.15.0
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: minitest
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: '0'
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: '0'
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/rails_server.rb
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/remote_shell.rb
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/database.rb
116
- - lib/conjure/log.rb
117
- - lib/conjure/config.rb
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: 1.8.25
145
+ rubygems_version: 2.2.1
146
146
  signing_key:
147
- specification_version: 3
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
-