Chef is a pull model it's up to the clients to request their configuration. If you want to push you'll have to inject something else in to allow you to do that. A command dispatcher which can invoke the client to contact the server when you want.
If you want to do the same thing over and over it feels like creating a LWRP http://wiki.opscode.com/display/chef/Lightweight+Resources+and+Providers+(LWRP) might be your best bet. You could then pass into it the variables you have and that way the code doesn't need reproduced X times.
If you didn't want to have to create new recipes for each install one other option would be to use the JSON mash capabilites in the attributes object and loop through a collection of objects creating the installs. This way it's data driven but personally I would look to use different recipes per install as it would probably be more transparent to people viewing the runlist.
An example of using the attributes mash is shown below. You could acheive this with a databag as well. In this case you could then update the JSON representation in a file and upload with knife or make the changes in the UI. Again I would recommend a recipe per site for transparency but that would lead to code/updating runlists etc
Your attribute json object would look a bit like this or similar
"drupal_Sites" : {
"site1": { "username": "dave", "password" :"password123", "URL":"www.madeup.com" },
"site2": { "username": "dave2", "password" :"password12", "URL":"www.madeup2.com" }
}
Then in your recipe it would be something like this
node["drupal_sites"].each do | site |
Install = yourdrupalcookbook_InstallResource "#{site['URL']}" do
username site['username']
password site['password']
deploy site['URL']
action :nothing
provider "yourdrupalcookbook_InstallProvider"
end
Install.run_action(:create)
end