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 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
-