Configure domain name outside the source control - ruby-on-rails

I have a Rails application which I now plan to deploy many instances to different domains. Originally I only intend for it to be on one domain.
I realize that for each domain, I have to replace all the hard-coded values in various places. These include:
asset host path (assets reside on the same domain)
whenever-gem's :application setting (since two domain can share the same server, and this is to avoid crobtab update clash)
some of tasks which uses curl to its own address to trigger events
carrierwave needs a hardcoded value when computing image full url without the request object.
Question
Is there a strategy to set this, so:
the setting should not be commited into source control (like database.yml.example)
Codes outside Rails can access it (whenever-gem does not load Rails environment)
Ways to access the domain can be consistent

One approach you can take is to have a YAML file with per deployment properties. You could even check the development version in and have your deploy scripts overwrite with the correct version.
Typically I'd put that configuration file in shared/config (assuming a capistrano style layout) and then symlink it into the current release during the deploy.

Related

How do I configure two sets of hosts (3 for QA and 3 for Prod) for deploying a distributed system using Spinnaker?

I am using Spinnaker to deploy a 3-tier system to QA and then to Production. Configuration files in each of these systems point to others. If I bake in the configuration for QA in the AMI, then how do I change it while promoting to Prod? Is it 1) by having two different sets of AMIs - one for QA and one for Prod, or, 2) by having the AMIs with no configuration and then configure it (somehow) after deployment to change the configuration files?
What is recommended?
You can define custom AWS user data for cluster at deploy time ( under advanced settings of the cluster configuration ). You can then retrieve this user data in your application. This will allow you to change these type of configurations.
At Netflix, we have a series of init scripts that are baked into the base image and provide a mechanism for extending custom startup ( init.d ) scripts via nebula / gradle. This usually sets values like NETFLIX_ENVIRONMENT that are well known and programmed against.
We also use a feature flipping mechanism via https://github.com/Netflix/archaius . This allows us to add properties that are external to the clusters but can be targeted towards them.
When it comes to secured credentials, the approach is outlined in this presentation, but essentially the images reach out to an external service that issues these type of creds. https://speakerdeck.com/bdpayne/key-management-in-aws-how-netflix-secures-sensitive-data-without-its-own-data-center
I am struggling with similar problems myself in our company.
My solution was to create AMIs for specific purposes using a Packer script. This allows me to -
1. Configure the server as much as I can and then store those configurations in an AMI.
2. Easily change these configurations if the need arises.
Then, launching the AMI using an Ansible script, and make all the rest of the configurations on the specific instance.
In my case I chose creating different images for staging and production, but mostly because they differ greatly. If they were more alike I might have chosen using a single AMI for both.
The advantage Ansible gives you here is factoring your configurations, and including written once to both production and staging servers.

developing several projects locally: How to configure environment variables

let's say I am developing 2 applications for 2 different clients which are, using 2 different database-configurations.
When using Openshift and CakePHP it is considered good practise to not store the real connection-info in the configs, but instead to use environment-variables.
That way the GIT-Repo is also always clean of server-specific stuff.
That is all fine as long as I have ONE project but as soon as there is another one, I need to override my local env-vars according to the current project.
Is there any way to avoid this? Is it possible to set up env-vars on my local machine per directory or something like that?
I am running OSX with Mamp Pro.
This may not be the best solution, but It would work. Create a different user on your local machine and then change to that other user when you need to access those other environment variables.
I create a 'data' directory in my git repo and set it to ignore. This way anything in there will be saved in the repo and sent to openshift. I place a config.ini file with all the info that I don't want in my repo.
I then manually put that config.ini file in Openshift's persistent DATA directory by using winSCP. You only have to do this when you change your config.ini.
When my app runs it detects if it's local or on Openshift and loads the config.ini file from the correct directory.
I would be interested if somebody has a better idea.
HTH

Grails: Two Sites, One Codebase

I have a sizable Grails application that has a small handful of controllers and views, and a very large number of Services.
I now need to build a "reskinned" version of the same site which has its own set of views and controllers (there are some smallish differences in how the controllers work), but the exact same set of Services. One option is to move all of the services into some kind of common place via custom Grails plugins, but I'm wondering if there's another way.
What I'd like to do is have two packages in the controllers folder, com.company.sitea and com.company.siteb, with an environment variable that effectively chooses which one of those is used. Similarly, two different sets of views, each one selected based on this environment variable, but with a shared taglib.
I was unable to find anything obvious that did this, is there a plugin or a standard way of doing this (or something similar)? The idea is, I'd have one codebase, I'd build one war, but the war would be deployed in two different places, and each one of those would specify a value for a special environment variable.
We have been successfully using a pattern where we make the first application a plugin. It will be run as an application for the first use case and included as a plugin to the second use case.
If you do this (a grails application is a application and plugin at the same time), you have to exclude the plugin from starting up when it's run as an application. Otherwise the application will start it self twice: as an application and as a plugin. The "grails.plugin.excludes" configuration setting (explained here) prevents this from happening.
I have documented this special use case in this jira issue:
http://jira.grails.org/browse/GRAILS-6751
"Allow a Grails application to be used as a Grails plugin besides using it as an application"
This has turned out to be a killer feature for us in many cases. We have been able to reuse applications as plugins in other use cases and combine several separate applications to one with this feature. Of course there are some restrictions (like name conflicts) but that hasn't been a problem for us.
The most common use case is to reuse a full application and just override the views in another one. Since an existing application can be an application and plugin at the same time, there is no extra work in extracting "common parts" to a separate plugin.
To make an existing Grails application a plugin you just have to add a MyAppNameGrailsPlugin.groovy file to the root directory and add this configuration value to grails-app/conf/Config.groovy:
grails.plugin.excludes = ['myAppName'] (application name in camel case starting with lower case letter)
Mailing list discussion:
http://grails.1312388.n4.nabble.com/Dynamic-applications-extending-an-existing-application-with-Grails-tp4634094p4634202.html
Burt's detailed blog post:
http://burtbeckwith.com/blog/?p=1973
David Dawson's presentation:
http://skillsmatter.com/podcast/home/large-scale-grails-using-plugins-how-to-modularise-an-application/jd-8012
one important factor is whether both of these versions should operate on the same data? so they will be different front-ends over same database? or they will be completely separate, for example per-customer deployment?
if the first, I would go webservices way, so one app would contain business logic, and controllers working as webservices, and other app would just have different controller, "talking" to the first one
you could also combine everything in one project (both versions) and limit access to different controllers from different domains with apache unmounts
if the latter, I would also try to extract common part into a plugin

How do I access a configuration variable passed into grails from the commandline

I am trying to send a variable to my grails app through the command line similar to this:
grails -Dmy.build.number=33 prod war ROOT.war
I have tried to access it as grailsApplication.config.my.build.number but I get an empty map. It seems odd that the variable is defined but not set to what I send.
How do I access the command-line property?
I am planning on putting some of my assets(css,js,images,etc) in cloudfront to act as a cdn. So in my build phase I want to use the build number as a cache buster and set my assets to point to mycloudfronturl/assets/${buildnumber}/script.js. If there is a better approach, I'm open to that as well.
System.getProperty("my.build.number");

ASP.NET MVC and multiple environments

How does ASP.NET MVC, if at all, deal with or provide ways to create your application using multiple environments? For example:
Development environment (local machine, probably run via the built-in web server and talking to a local database)
Testing (runs against a preloaded databse with example data, although this part could be skipped and mocks could be used)
Production database on a real server with real data
Ruby on Rails has the concept of environments and "automagically" can deduce if you're in development or production, so you can specify your connection information (connection string) in a config file and the framework dynamically pulls the appropriate one. Is there a similar way of doing things with .NET MVC? If not then how are professional developers using .NET MVC handling different environments?
The only way I can think of is to manually add an "environment" global method (or use an enum, or something like that, maybe this is a use for something like the State pattern?) and store the different connection strings in the web.config file, and then create a base class which all data access classes derive from which provides a way to obtain the connection string for the current environment; this would then have to be set to production when the time comes to put the application live.
Is there another way? Most of the .NET MVC videos and articles I've seen don't even bother with separate environments but only use a development database and don't indicate how you do it in production.
I'd say this is really a question of your company's internal processes. Since every company is a little bit different it's hard to have a "right" generic way to support dev/test/alpha/production and/or other environments.
One way: Create a setup program that supplies the correct connection string based on the environment chosen during the setup process.
Another way: System Admin edits web.config file to supply correct connection string during install.
Yet ANother Way: Connection strings are stored in the system registry.
Even Another Odd Way: You have all your connection strings for all environments in web.config, then a setting in appSettings the tells you which one to use.
Depending on the client, I've done all of these. There are more but these are the more popular.
(One client wanted to store the connecting string in the data base itself. Really.)
You can use alias for your database. You just point these aliases to different servers in the different environments. Stored in the registry under HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSSQLServer\Client\Connect if i remember right. Then you use the alias in the connectionstring.
In response to Jason's response:
We use Enterprise Library Environments to configure the different environment paramters and via msbuild invoke the Merge Configuration Tool that generates the different configs for each environment. The deploy process picks the right config file depending on which environment to install.
I was able to solve a similar situation following these steps:
In your Visual Studio, access Build > Configuration Manager
Click in "new"
Choose a name for your configuration, and then copy settings from an existing config. After the configuration creation, it will be available for you to target as build configuration
Create a Web.{env-name-you-chose}.config in your application folder, along with the original Web.config file.
Open your .csproj file with Visual Studio or any text editor
Search for a section that looks like the following and add the highlighted lines, with the config file name you gave previously:
Open your Visual Studio, reload projects if it's required, and now you are able to choose your configuration via CLI or manual publish using Visual Studio.
There is a Publishing Wizard (in Visual Studio) wich let's you change parts of web.config for release build automaticaly. Wich happens to be the feature you are asking about. No magic thou.
What we have done is during our automated build process (Hudson), we alter values in web.config depending on which environment the build is for. Unfortunately there isn't a magical way to do this.
For deployment, which I assume that is what the op was asking about, one creates multiple configurations and in the publish, picks a different configuration. These are called transforms and they operate on the web.config. One would have at least three publish profiles, one for dev, test and prod. One can change more than just the connection string in this way. One can turn on custom errors, turn off debugging and change values of configuration variables. I highly recommend it.
I have a similar question. I have a log table reader. I want it to read log tables in the development, test and production databases. The major difficulty lies in my user account doesn't have permission to look at test and production. It's some silly security thing. The user that I'm impersonating in the application does have permission. I'm struggling trying to tell MVC to build the test and production models using the impersonated user.

Resources