How to determine at runtime if I am connected to production database? - sql-server

OK, so I did the dumb thing and released production code (C#, VS2010) that targeted our development database (SQL Server 2008 R2). Luckily we are not using the production database yet so I didn't have the pain of trying to recover and synchronize everything...
But, I want to prevent this from happening again when it could be much more painful. My idea is to add a table I can query at startup and determine what database I am connected to by the value returned. Production would return "PROD" and dev and test would return other values, for example.
If it makes any difference, the application talks to a WCF service to access the database so I have endpoints in the config file, not actual connection strings.
Does this make sense? How have others addressed this problem?
Thanks,
Dave

The easiest way to solve this is to not have access to production accounts. Those are stored in the Machine.config file for our .net applications. In non-.net applications this is easily duplicated, by having a config file in a common location, or (dare I say) a registry entry which holds the account information.
Most of our servers are accessed through aliases too, so no one really needs to change the connection string from environment to environment. Just grab the user from the config and the server alias in the hosts file points you to the correct server. This also removes the headache from us having to update all our config files when we switch db instances (change hardware etc.)
So even with the click once deployment and the end points. You can publish the a new endpoint URI in a machine config on the end users desktop (I'm assuming this is an internal application), and then reference that in the code.
If you absolutely can't do this, as this might be a lot of work (last place I worked had 2000 call center people, so this push was a lot more difficult, but still possible). You can always have an automated build server setup which modifies the app.config file for you as a last step of building the application for you. You then ALWAYS publish the compiled code from the automated build server. Never have the change in the app.config for something like this be a manual step in the developer's process. This will always lead to problems at some point.
Now if none of this works, your final option (done this one too), which I hated, but it worked is to look up the value off of a mapped drive. Essentially, everyone in the company has a mapped drive to say R:. This is where you have your production configuration files etc. The prod account people map to one drive location with the production values, and the devs etc. map to another with the development values. I hate this option compared to the others, but it works, and it can save you in a pinch with others become tedious and difficult (due to say office politics, setting up a build server etc.).

I'm assuming your production server has a different name than your development server, so you could simply SELECT ##SERVERNAME AS ServerName.

Not sure if this answer helps you in a assumed .net environment, but within a *nix/PHP environment, this is how I handle the same situation.
OK, so I did the dumb thing and released production code
There are a times where some app behavior is environment dependent, as you eluded to. In order to provide this ability to check between development and production environments I added the following line to global /etc/profile/profile.d/custom.sh config (CentOS):
SERVICE_ENV=dev
And in code I have a wrapper method which will grab an environment variable based on name and localize it's value making it accessible to my application code. Below is a snippet demonstrating how to check the current environment and react accordingly (in PHP):
public function __call($method, $params)
{
// Reduce chatter on production envs
// Only display debug messages if override told us to
if (($method === 'debug') &&
(CoreLib_Api_Environment_Package::getValue(CoreLib_Api_Environment::VAR_LABEL_SERVICE) === CoreLib_Api_Environment::PROD) &&
(!in_array(CoreLib_Api_Log::DEBUG_ON_PROD_OVERRIDE, $params))) {
return;
}
}
Remember, you don't want to pepper your application logic with environment checks, save for a few extreme use cases as demonstrated with snippet. Rather you should be controlling access to your production databases using DNS. For example, within your development environment the following db hostname mydatabase-db would resolve to a local server instead of your actual production server. And when you push your code to the production environment, your DNS will correctly resolve the hostname, so your code should "just work" without any environment checks.

After hours of wading through textbooks and tutorials on MSBuild and app.config manipulation, I stumbled across something called SlowCheetah - XML Transforms http://visualstudiogallery.msdn.microsoft.com/69023d00-a4f9-4a34-a6cd-7e854ba318b5 that did what I needed it to do in less than hour after first stumbling across it. Definitely recommended! From the article:
This package enables you to transform your app.config or any other XML file based on the build configuration. It also adds additional tooling to help you create XML transforms.
This package is created by Sayed Ibrahim Hashimi, Chuck England and Bill Heibert, the same Hashimi who authored THE book on MSBuild. If you're looking for a simple ubiquitous way to transform your app.config, web.config or any other XML fie based on the build configuration, look no further -- this VS package will do the job.
Yeah I know I answered my own question but I already gave points to the answer that eventually pointed me to the real answer. Now I need to go back and edit the question based on my new understanding of the problem...
Dave

I' assuming yout production serveur has a different ip address. You can simply use
SELECT CONNECTIONPROPERTY('local_net_address') AS local_net_address

Related

SSIS - best practices for connection managers -- compose out of parameters?

I've worked a lot with Pentaho PDI so some obvious things jump out at me.
I'll call Connection Managers "CMs" from here on out.
Obvious, Project CMs > Package CMs, for extensability/ re-usability. Seems a rare case indeed where you need a Package-level CM.
But I'm wondering another best practice. Should each Project CM itself be composed of variables? (or parameters I guess).
Let's talk in concrete terms. There are specific database sources. Let's call two of them in use Finance2000 and ETL_Log_db. These have specific connection strings (password, source, etc).
Now if you have 50 packages pulling from Finance2000 and also using ETL_Log_db ... well ... what happens if the databases change? (host, name, user, password?)
Say it's now Finance3000.
Well I guess you can go into Finance2000 and change the source, specs, and even the name itself --- everything should work then, right?
Or should you simply build a project level database called "FinanceX" or whatever and make it comprised of parameters so the connectoin string is something like #Source + # credentials + # whatever?
Or is that simply redundant?
I can see one benefit of the parameter method is that you can change the "logging database" on the fly even within the package itself during execution, instead of passing parameters merely at runtime. I think. I don't know. I don't have a mountain of experience with SSIS yet.
SSIS, starting from version 2012, has SSIS Catalog DB. You can create all your 50 packages in one Project, and all these packages share the same Project Connection Managers.
Then you deploy this Project into the SSIS Catalog; the Project automatically exposes Connection Manager parameters with CM prefix. The CM parameters are parts of the Connection Manager definition.
In the SSIS Catalog you can create so called Environments. In the Environment you define variables with name and datatype, and store its value.
Then - the most interesting part - you can associate the Environment and the uploaded Project. This allows you to bind project parameter with environment variable.
At Package Execution - you have to specify which Environment to use when specifying Connection Strings. Yes, you can have several Environments in the Catalog, and choose when starting Package.
Cool, isn't it?
Moreover, passwords are stored encrypted, so none can copy it. Values of these Environment Variables can be configured by support engineers who has no knowledge of SSIS packages.
More Info on SSIS Catalog and Environments from MS Docs.
I'll give my fair share of experience.
I recently had a similar experience at work, our 2 main databases name's changed, and i had no issue, or downtime on the schedules.
The model we use is not the best, but for this, and for other reasons, it is quite confortable to work with. We use BAT files to pass named parameters into a "Master" Job, and basically depending on 2 parameters, the Job runs on an alternate Database/Host.
The model we use is, in every KTR/KJB we use a variable ${host} and ${dbname}, these parameters are passed with each BAT file. So when we had to change the names of the hosts and databases, it was a simple Replace All Text Match in NotePad++, and done, 2.000+ BAT Files fixed, and no downtime.
Having a variable for the Host/DB Name for both Client Connection and Logging Connection lets you have that flexibility when things change radically.
You can also use the kettle.properties file for the logging connection.

Is using ENV variables a good idea?

Background
Our app uses a MySQL DB and a couple more services.
To connect our app to these servers, we have the usernames and passwords saved in a prod.config file. If we are in dev, we use a dev.config file and so on...
Recently, I have been studying good practices in the industry ( such as the https://12factor.net/ ) and the majority of them ( if not all ) specify that information like usernames and pwd's to connect to DB and other services should not be in conifg files but rather in ENV variables.
If you have no idea what the 12 factor spec is you can check this free tutorial:
https://egghead.io/lessons/egghead-summary-concepts-of-the-twelve-factor-app
Problem
Now, at first this looks fine. Many CI tools like Travis or CircleCI already force you to do this anyway. The problem here is when your smallest app uses multiple services.
In our case, for our smallest app, we would need 13 ENV variables. Variables that wouldn't be in any specific file, they would all have to be in the ENV of the machine they run on.
I fail to see how this can be seen as a good practice. I understand the main idea of not pushing your confg files with all this sensitive data, but this approach poses several issues:
When the machine reboots, you loose all you ENV variables.
If you want to avoid the previous problem, you need to run a script on machine start, that sets these said variables, which means you would have them stored in a file, defeating the whole purpose.
Where do you save these variables? They need to be somewhere else other than you flimsy head!
Questions
How would I solve the previous issues?
Why is saving private info in ENV variables seen as a good idea?
I'm going to step back a bit here and pose a question to you: why are you trying to connect to a production database from a testing environment?
The beauty of CI tools is that they allow you to spin up Docker containers to act as testing services. In your production code, it is considered best practice to keep your passwords saved in environmental variables for two main reasons:
1.) If someone ever got a hold of your code, they would have access to your database. It requires an extra level of security that is just not realistic.
2.) If someone did get a hold of your passwords, you want to be able to change them quickly. This is easier to do if your code references environmental variables instead of hard-coded strings.
When you move to a CI system, point #2 becomes moot, but point #1 becomes exceedingly important. With Travis and CircleCI, your config file is public. If you put your production password into your config file, I (or someone much more malicious) could just go scan your file and jump into your database. I've heard stories of hackers scraping public repositories for hardcoded passwords in config files. It's even easier with a tool like CircleCI.
The environmental variables you set in Travis and CircleCI should be stored at a repository level- you shouldn't need to move variables around or save them.
Environmental variables in a production system should be set-up as part of a startup script. This is highly dependent on what kind of service you're using, so I won't go into much detail here.

Web-App : Keeping trace of the version of the application in database?

We are building a webapp which is shipped to several client as a debian package. Each client runs his own server. But the update and support is done by us.
We make regular releases of the product, with a clean version number. Most of the users get an automatic update (by Puppet), some others don't.
We want to keep a trace of the version of the application (in order to allow the user to check the version in an "about" section, and for our support to help the user more accurately).
We plan to store the version of the code and the version of the base in our database, and to keep the info up to date automatically.
Is that a good idea ?
The other alternative we see is a file.
EDIT : The code and database schema are updated together. ( if we update to version x.y.z , both code and database go to x.y.z )
Using a table to track every change to a schema as described in this post is a good practice that I'd definitely suggest to follow.
For the application, if it is shipped independently of the database (which is not clear to me), I'd embed a file in the package (and thus not use the database to store the version of the web application).
If not and thus if both the application and the database versions are maintained in sync, then I'd just use the information stored in the database.
As a general rule, I would have both, DB version and application version. The problem here is how "private" is the database. If the database is "private" to the application, and user never modifies the schema then your initial solution is fine. In my experience, databases which accumulate several years of data stop being private, it means that users add a table or two and access data using some reporting tool; from that point on the database is not exclusively used by the application any more.
UPDATE
One more thing to consider is users (application) not being able to connect to the DB and calling for support. For this case it would be better to have version, etc.. stored on file system.
Assuming there are no compelling reasons to go with one approach or the other, I think I'd go with keeping them in the database.
I'd put them in both places. Then when running your about function you quickly check that they are both the same, and if they aren't you can display extra information about the version mismatch. If they're the same then you will only need to display one of them.
I've generally found users can do "clever" things like revert databases back to old versions by manually copying directories around "because they can" so defensively dealing with it is always a good idea.

Can connectionstring cross over to other sites on the same server?

I ran across a new problem in the last week. Due to the nature of my project and available budget a small intranet web application I've been working on is both the testing and live server, as well as serves up the pages and is the sql server. This will last at least until the project is out of the major development cycle. Now that the project has real users but I am continuing development I duplicated the database to have a safe copy to mess with that won't cause havoc to live business data and a development copy of the website.
All was well until I discovered an anomoly on the test copy of the site, anything that uses a sql datasource was properly pulling it's data from the test database, but anything that gets it's data from a stored procedure triggered in the code behind was pulling it's data from the live databse.
My confusion comes from the fact that all stored procedures and sql datasources ultimately point back to the same connectionstring setting in the web.config file to know where to connect to. I just rename the database name depending on if I'm uploading the latest changes to the test or live site.
My question comes down to, why would with one connection string in each site would my test site accessing data one way get it from one database and accessing the other get it's data from the other database?
Here's my connection string they all point back to, names/passwords of course change for obvious reasons, but the structure is intact.
<add name="db_Connection" connectionString="Data Source=SERVERNAME;Initial Catalog=DATABASE_live;Persist Security Info=False;User ID=USERID;Password=password" providerName="System.Data.SqlClient"/>
I added a key to the appsettings to reference the name of the database connection so I could easily change it's name if need be without having to edit dozens of pages for the code behind SProc calls.
<add key="defaultDB" value="db_Connection" />
Am I violating some rule I'm unaware of or is there something else going on that I need to be aware of and change so I can have a true test environment as I continue to develop an active site?
EDIT This project is in ASP.NET 2.0 VB, fixed the code display.
solution found I have tracked down the solution, thanks for the pointers, they got me looking elsewhere. When I copied the site to a different location for testing I forgot to update my appsetting key for the site's location, this caused the following part of the call for stored procedures to grab data from the live site's web.config aparently.
System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration(pubvar_webConfig)
Change the username and password on the dev database. If your problem persists then you might have a connection string set somewhere else that you don't know about.
I would search all of the files in your solution to make sure you don't have one of the database names hard coded some place. Maybe in the designer files?
It may be worth running the two applications in different app pools via IIS (if you aren't already or course!). This should eliminate any concurrency issues between the test and production sites at the application level.
IMHO with a shared test / production environment seperate app pools is good practice at any time.

Best Practice for seeing live data on the dev server?

Assumption: live/production web app suppresses errors being shown to end-users.
Suppose your tech support team wants to see live data but through the eyes of the development-side of the application (maybe you want to see what errors are occurring, or want to see when you've got an issue fixed using an end-user's data).
Right now we've got one database serving both the dev and live boxes (not my idea - I know it's gross).
Ideas?
Edit: Best/handy tools for implementing your suggestion?
We replicate the data back to a different database. Yes, there is a delay, but it keeps people hands out of the production servers. This also allows us to "hide" information that tech support (and other people for that matter) aren't supposed to see.
In addition to replicating data down, on production, we see who's logged into the application, and if it's a member of the company, send them to the real error page versus the happy kitten playing with a ball of yarn apologizing.
Back up and restore from live to dev on a regular basis (once, twice a day). It doesn't need to be realtime (as you might be entering data from the dev side anyway, which could cause problems).
If you have PCI or HIPAA data, make sure you don't put that in your dev environment -- that might break laws.
I generally like to have a 3-tier system for web development:
Development
Testing
Live
Most of the time testing is an exact copy of the live system, except that errors are turned on, when a new version is about to be moved live it's replaced with the new version BEFORE live is, to detect upgrade issues.
Development is completely separate from live, to allow for major changes to things like the database, or changes to the production environment.
I would firstly make errors are either emailed to someone with details of how the user got there or at minimum logged so you can watch the error log while you perform similar actions to see if you get the same messages in the log.
And yes, copying the database on the dev server/site is probably your only option. You don't want any changes made by the development team to live data and you'll probably also have changes that won't work with the production database at some point.
I wouldn't recommend doing a nightly copy as a developer might be in the middle of some new feature where they have added data and then it's erased that night. I usually copy the production database(s) to dev each time a major version is released. This also allows me to do speed testing with a lot of live data. On some systems I also change everyones password to a default so I can login easily as any user.
If your configuration permits it:
a. Add a logging function (if there isn't one already) to write messages of interest to a log file.
b. Run the unix command
tail -f < logfile.txt
which will stream the growing log file to your console.
http://www.monkey.org/cgi-bin/man2html?tail
If you have Windows, you might try this:
http://tailforwin32.sourceforge.net/

Resources