Change repository dynamically

711 views
Skip to first unread message

shrinath_m2

unread,
Jun 8, 2012, 2:30:12 AM6/8/12
to capis...@googlegroups.com
Hi all, 

I have a specific requirement: 

  1. We have 10 machines on which specific codes are deployed. 
  2. Codes are in SVN. 
  3. Out of those 10, we sometimes want 1 or 2 of the machines to point to a different SVN repo/path. 
I have all the server IPs in mysql, I fetch them into my recipe using queries to db, then loop and add them to role :app. 
Now with the above mentioned requirements, I thought of adding SVN repo URL to the mysql too, so that every IP has the associated SVN URL that shall be deployed to it. 

Now how do I switch repo dynamically in deployment procedure? 
Any suggestions welcome. 

Regards, 
Shrinath M

Lee Hambley

unread,
Jun 8, 2012, 2:48:16 AM6/8/12
to capis...@googlegroups.com
Shrinath,

Sorry that's simply not possible; the core configuration variables are shared between each server, and cannot be changed on a per-host basis.

- Lee
--
* You received this message because you are subscribed to the Google Groups "Capistrano" group.
* To post to this group, send email to capis...@googlegroups.com
* To unsubscribe from this group, send email to capistrano+...@googlegroups.com For more options, visit this group at http://groups.google.com/group/capistrano?hl=en

shrinath_m2

unread,
Jun 8, 2012, 3:19:36 AM6/8/12
to capis...@googlegroups.com
Thanks for the straight forward reply, it saved lot of hair pulling time :)
I'll think of re structuring the things then...
If you have any suggestions regarding how it can be structured, then let me know...

Regards, 
Shrinath M
* To unsubscribe from this group, send email to capistrano+unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/capistrano?hl=en

Lee Hambley

unread,
Jun 8, 2012, 3:22:17 AM6/8/12
to capis...@googlegroups.com
Shrinath,

Just to clarify a little, the blocks which are passed to the server to execute are evaluated once, and then passed to each connected server, thus there's no way to do something in the `update_code` task such as `svn checkout #{this_server[:svn_url]}`. 

A similar manifestation of this problem is people trying to put one configuration file, by name to each server.

We're working on a major rewrite and this is one of the problems that we have in mind, restructuring the way these things are done, so that the block is run in the context of the server, per server.

Unfortunately I can't commit to a timeline for that work now; please just watch this space!

- Lee
* To unsubscribe from this group, send email to capistrano+...@googlegroups.com For more options, visit this group at http://groups.google.com/group/capistrano?hl=en

Donovan Bray

unread,
Jun 8, 2012, 10:55:43 AM6/8/12
to capis...@googlegroups.com
My first reaction is that you will have to do two deploys ie in two stages one for each repo. 
--

Shrinath M

unread,
Jun 8, 2012, 11:52:01 AM6/8/12
to capis...@googlegroups.com
And how would I do that? 
Make a custom task and call deploy twice in it with different repo settings? 
--
Regards
Shrinath M

Donovan Bray

unread,
Jun 8, 2012, 9:56:57 PM6/8/12
to capis...@googlegroups.com
It's hacky but I've done something like this before: I call this pattern cannibalistic capistrano. 

task :p1 do
  set :repository, '....xyz'
  server ....
end

task :p2 do
  set :repository, '....abc'
  server ....
end

task :both do
  namespace :deploy do
    task :default do; end
  end
  %w(p1 p2).each do  |stage|
     run_locally "cap #{stage} deploy"
  end
end

You should be able to do any of the following:

cap p1 deploy
cap p2 deploy
cap both deploy

shrinath_m2

unread,
Jun 11, 2012, 3:07:24 AM6/11/12
to capis...@googlegroups.com
Tried that, but there is a problem - calling the "run_locally 'cap deploy'" does all the initialization from beginning... I don't really want that - 
isn't there a way to call "deploy" as a task or something? Like so: 

task :a1 do
  a2
end

task :a2 do
  deploy #calls the default deploy?
end

I should be doing cap -S whatever=wherever a1 and thus starting the deployment. 

I tried the above, but having "deploy" in a task doesn't seem to be doing anything :(
* To unsubscribe from this group, send email to capistrano+unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/capistrano?hl=en

--
* You received this message because you are subscribed to the Google Groups "Capistrano" group.
* To post to this group, send email to capis...@googlegroups.com
* To unsubscribe from this group, send email to capistrano+unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/capistrano?hl=en



--
Regards
Shrinath M

--
* You received this message because you are subscribed to the Google Groups "Capistrano" group.
* To post to this group, send email to capis...@googlegroups.com
* To unsubscribe from this group, send email to capistrano+unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/capistrano?hl=en

Rafa García

unread,
Jun 11, 2012, 5:18:29 AM6/11/12
to capis...@googlegroups.com
Try with the task "deploy.default" (when you do "deploy" you're calling "deploy:default").

If you're inside of a namespace "top.deploy.default" , it goes to top parent namespace and look for deploy:default.

Regards

2012/6/11 shrinath_m2 <cool....@gmail.com>
* To unsubscribe from this group, send email to capistrano+...@googlegroups.com For more options, visit this group at http://groups.google.com/group/capistrano?hl=en

Shrinath M

unread,
Jun 11, 2012, 8:05:28 AM6/11/12
to capis...@googlegroups.com
Good! That "deploy.default" works... 
May be I should have learn't a bit of ruby, rake and things before dropping right in...

Thanks :)
--
Regards
Shrinath M

Donovan Bray

unread,
Jun 12, 2012, 1:17:21 AM6/12/12
to capis...@googlegroups.com
It may appear to work at first glance but you'll be surprised what doesn't get re-evaluated the second time you call deploy.default in the same process. 

The method I described to you starts the each underlying deploy with a clean ruby process. 

Shrinath M

unread,
Jun 12, 2012, 4:50:46 AM6/12/12
to capis...@googlegroups.com


On Tue, Jun 12, 2012 at 10:47 AM, Donovan Bray <donn...@gmail.com> wrote:
with a clean ruby process. 
That exactly is my problem - I am passing few custom variables - like "cap -S config=myconf -S svn_repo=staging -S restart_bin=httpserver task_a" 
Now, if I do as you say, I'll have to pass them all over again, which will re-initiate the whole bootstrapping... Bad, isn't it? That requires lot more re-structuring...

BTW, what might not work with the accepted approach - deploy.default? 



--
Regards
Shrinath M

shrinath_m2

unread,
Jun 12, 2012, 11:03:10 AM6/12/12
to capis...@googlegroups.com
OK, now I am stuck in something interesting...

My logic to achieve the above said requirement is as follows: 

You call "cap -S config=blah -S svn-repo=both my_deploy"

The code in deploy.rb is as such: 

  
task :my_deploy do                                                            
  init_server_list { deploy.default }                                         
end

def init_server_list(&given_task)

  # if svn repo name is given, get ip from there. 
  if variables.include?(:svn_repo) and svn_repo == "both"
    # get all repo names, call deployer for every unique name.  
    con = Mysql.new(db_host, db_user, db_pass, db_schema)
    rs = con.query("SELECT DISTINCT _nick_name FROM repo;")
    rs.each do |row|
      set :repo_name, row[0]
      get_server_list given_task
    end
    con.close
  end
end


def get_server_list(action)
  con = Mysql.new(db_host, db_user, db_pass, db_schema)
  query = "select 
          server.`_ip` as ip,
          repo.`_svn_url` as repo_url
        from
          server 
          left join repo
            on repo.`_id` = server.`_repo_id`
        where repo.`_nick_name` = '#{repo_name}'";

  rs = con.query(query)                                                       
  roles[:app].clear

  rs.each do |row|
    role :app, row[0]
    set :repository, row[1]
  end
  con.close
  action.call
end

# Unnecessary code removed and/or obfuscated, but assure that no harm done to hinder debugging. 

Now the logic is that it should loop through for every repository, get the list of servers to be updated for that repository and update the code. 
All is well, it runs smoothly for every server and all... But...
When it comes to updating the svn repo, it is pushing the same repo that it got first time. 
It seemed that the "svn checkout" command is cached somewhere...

Further debugging, I went into "strategy/checkout.rb" inside capistrano's code. 

def command
  @command || = source.checkout(revision, configuration[:release_path])
end

Remove the '||' there, it works well... I wouldn't like to touch original capistrano code unless absolutely necessary. So, is there a way to unset the command variable from my recipe or any better way? 
Any suggestions towards the architecture or a solution would be welcome... 

Donovan Bray

unread,
Jun 12, 2012, 11:39:54 AM6/12/12
to capis...@googlegroups.com
You can make the :both task smarter. 

task :both do
  %w(p1 p2).each do  |stage|
     run_locally "cap #{ARGV.map{|a| a=='both' ? stage : a }.join(' ')}"
  end
  exit 0 #don't call any more tasks in this process
end

In answer to your second question there's no way to qualify how many things won't be re-evaluated by calling deploy.default in the same process multiple times; the more recipes you use the more chances you have for it to screw you. 

Off the top of my head I would think you would see this issue if you attempt to set a different deploy_to between stages. 

Donovan Bray

unread,
Jun 12, 2012, 11:49:05 AM6/12/12
to capis...@googlegroups.com
And you've hit exactly what I warned you about; and it wont likely be your last. 

Shrinath M

unread,
Jun 12, 2012, 12:24:00 PM6/12/12
to capis...@googlegroups.com


On Tue, Jun 12, 2012 at 9:19 PM, Donovan Bray <donn...@gmail.com> wrote:
And you've hit exactly what I warned you about; and it wont likely be your last. 

Lol :D  True...

Then I'll try changing my way to go with run_locally method you suggested 2 posts above... Better re structure at initial level than at further stages...

That might take a day more, will report back if I hit something by then...



--
Thanks,
Shrinath M

shrinath_m2

unread,
Jun 13, 2012, 5:48:01 AM6/13/12
to capis...@googlegroups.com
If I do run_locally, its not outputting my "puts" statements :( 
What am I missing? 

* To unsubscribe from this group, send email to capistrano+unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/capistrano?hl=en

shrinath_m2

unread,
Jun 13, 2012, 6:38:11 AM6/13/12
to capis...@googlegroups.com
before anyone asks why I want puts and why not "logger.info" or something alike, I have disabled capistrano's detailed logging with my own. 
That puts few things on screen and few on log files wherever necessary. 

Donovan Bray

unread,
Jun 14, 2012, 12:10:45 AM6/14/12
to capis...@googlegroups.com
puts I think is a cap helper to upload files

Try


Instead. 
* To unsubscribe from this group, send email to capistrano+...@googlegroups.com For more options, visit this group at http://groups.google.com/group/capistrano?hl=en

Donovan Bray

unread,
Jun 14, 2012, 12:11:23 AM6/14/12
to capis...@googlegroups.com
Try p instead of puts then
* To unsubscribe from this group, send email to capistrano+...@googlegroups.com For more options, visit this group at http://groups.google.com/group/capistrano?hl=en

shrinath_m2

unread,
Jun 14, 2012, 12:34:46 AM6/14/12
to capis...@googlegroups.com
Nope :(
Didn't work... 
Reply all
Reply to author
Forward
0 new messages