Automating SQL Server patching

Howdy everyone, today I’m gonna talk about SQL Server patching.

While this operation is pretty straightforward and very rarely causes issues by itself, there is nothing less entertaining than going from server to server, RDP to RDP, launching the same executable over and over. Which opens an automation opportunity for us!

Let me introduce you a new tool from the dbatools toolset: Update-DbaInstance. It will take care of SQL Server patching – and all the associated with it activities. It supports updating to latest or specific version of SQL Server, allows you to restart the computer after the upgrade is finished, and, most importantly, you can run it against multiple servers in parallel.

Prerequisites

Elevated session

This command is designed to be run in an elevated session. It is a must for the local installations, when you’re running the command against a localhost, but, strangely enough, it’s also required when you’re running it against remote machines and you patch repository is on a network drive (which I’m guessing is the case 99% of the time). Why? See the next prerequisite:

Powershell remoting and Credentials

Unsurprisingly, performing remote patching through Powershell requires Powershell remoting to be already configured. There is one more requirement, though, for running sessions remotely: if your patch repository is a network folder, there is no way default remoting session would be able to get them. It would run into the infamous double-hop issue and fail to delegate your current credentials when accessing that folder.

The solution to that is to pass credentials to the remote server, which would authenticate you on that remote server properly. This is why, specifying explicit -Credential parameter will help you in such scenarios. In such doing, you are implicitly switching to the CredSSP authentication protocol which allows you to securely pass credentials to the remote host.

Using CredSSP protocol without configuring it

The command will attempt then to configure CredSSP protocol on both client and server – this is why the elevated session is required even on the client machine. Such dynamic connection configuration is only supported on Powershell 3.0 or higher: both client and server should comply with this requirement.

Properly configured CredSSP with Credentials passed through the remote session

If for any reason, CredSSP configuration and/or connection has failed, the command will ask you if you want to try using a less secure protocol (Default) to pass credentials to the remote server.

With all that said, if the server is able to reach the patch file without authentication, you won’t need to specify credentials at all.

Patch repository

You’ll need to have you SQL Server update files stored somewhere where the server can reach them: a network drive or a local folder. The command would find relevant KB based on execution parameters and look for the file name recursively in specified path(s).

Important thing about the patch repository is that all the KB files should maintain their original naming, which in all cases follows a predefined file name template:

SQLServer*-KB*-*x*.exe

Having such file stored in the folder will ensure that the update command finds it among the files in the folder, but keep in mind that folders with huge number of files might slow down the search. You can specify this folder by using the -Path parameter.

Executing the command

There are a few ways you can execute the command and most of them are covered in the examples you can get from running Get-Help Update-DbaInstance -Examples

Never forget about the power of Get-Help

Some of the features worth mentioning:

  • By default the command will try to update the server to the latest-and-greatest service pack and cumulative update
  • You can specify -Type to choose between installing service packs, cumulative updates or both
  • -Restart will restart the computer after the installation is successful. Very helpful when installing multiple updates at once – each of them will require a restart. It will also restart the computer prior to installing the updates in case a pending restart is already queued in the system.
  • -Version will allow you to target a specific version of SQL Server on the machine, as well as define the update level you want to reach. Some of the examples:
    • SQL2008SP4 – upgrade all SQL2008 instances to SP4
    • 2012SP3CU11 – upgrade all SQL2012 instances to SP3 CU11
    • 2016 – upgrade all SQL2016 instances to the latest version available
    • SP4 – upgrade all instances found on the computer to SP4, regardless of their version
  • Specifying more than one computer in -ComputerName will initiate a parallel update once all the update paths have been discovered and confirmed
  • This command is considered as a high-risk command, which means it would ask you to confirm each update path before executing it. To disable that behavior use -Confirm:$false
  • It can be a good idea to run the command in the -WhatIf mode first to assess the impact of it.

A simple execution of the command will go through the following phases:

  • Search for existing installations of SQL Server
  • Check if there are any eligible updates for each chosen installation
  • Configure CredSSP for remote connections
  • Search for the required SQL Server KB file(s) in the repository path defined in -Path
  • Ask user’s permission to continue with the installation
  • Extract and install the update(s): service pack, then cumulative update.
  • Restart the computer if needed and -Restart is specified
Update process in all its glory

Conclusion

This command is designed to turn a mundane patching process into a simple task, which now can be performed often enough to keep up with the pace of SQL Server cumulative update releases. Hope you’ll find a use for it in upcoming 2019.

Merry Christmas and Happy New Year!

Special Agent Jenkins

I saw (and wrote myself) thousands of lines of Transact-SQL code that interacts with something outside of the SQL Server instance box: be it an executable file, or a remote query to a different SQL server, or something as simple as running a Powershell statement. I still remember how excruciatingly painful it is to wrap up simple OS commands into a string variable, feed it into xp_cmdshell, create tables to retrieve results, parse them using T-SQL… The list can go on and on, but the main idea is: such code is hard to read, even harder to maintain and a simply a nightmare to scale.

Nine times out of ten these scripts were triggered by a SQL Server Agent job; mostly, because, when it comes to scheduling, in 95% of the cases SQL Server administrators rely on SQL Server Agent – it is our ‘go-to’ solution. However, even while SQL Server Agent has many positive traits, it also has certain limitations in some of the scenarios. Most notable examples include (but not limited to):

  • Email interactions: basic notifications after job completion are usually not detailed enough. sp_send_dbmail in advanced use-cases as an attempt to overcome this deficiency forces us to write complicated logic inside our code to accommodate for various scenarios.
  • Interactions with remote SQL Servers: mostly relies on Linked Servers, which come with an overhead of additional maintenance. Requires advanced logic (and maintenance) if Availability Groups are involved – to decide whether the AG database is active on the current server.
  • Other remote interactions: Powershell remoting through CmdExec task running a Powershell script…? Writing results to a temporary table to pass it on to the next step? Using proxy accounts to interact with the network shares? There are many workarounds, but all of them require a wrapper of some kind, which, in addition to the complex syntax, are in most cases not overly secure.
  • Running code that comes from a different programming language: requires code interpreter to be installed on a SQL box, which I rarely consider a best approach, knowing how easy it is to forget about ‘custom‘ configuration. Powershell was an exception to that rule, except until SQL 2016 it only came as ‘SQL Server Powershell’ that had certain quirks and limitations. Debugging such steps was/is a nightmare of its own due to limited exception handling capabilities.
  • Capturing output (and storing it somewhere on the disk) has different flavors, but usually one of the following occurs:
    • There are thousands of log files in your log folder
    • All the logs are stored in msdb; comes with additional headache of retrieving them when needed, cleaning them up and including into the email notifications
    • Log file is configured to append output to the existing file and is now several megabytes long
    • You only have access to the latest execution log
  • Execution timeouts – ability to stop the job after certain duration can only be achieved by having yet another job to control that.

Now, I am not trying to say that SQL Agent should never be used. It is convenient and utterly reliable at some tasks, like running stored procs or native T-SQL on that same server; it can easily be managed by native SQL Server tools (SSMS, T-SQL); it has advanced options, such as multi-server management and so on. What I’m trying to say is: there are other options.

Jenkins – work smarter not harder

jenkins-ci_512
Mr. Jenkins himself with an automation towel

Jenkins is a well-known DevOps automation solution, and is widely used across the globe in all kinds of automation tasks. Once you familiarize yourself with Jenkins basic concepts, it becomes a powerful tool in your hands that allows you to build almost any chain of automation events, linking together tasks coming from different programming languages, applications or even operating systems.

More importantly here, Jenkins is completely independent of SQL Server, meaning that Jenkins jobs will continue to trigger and execute even when SQL Server is not running; jobs will be able to talk directly to Availability Group listeners instead of deciding whether or not to run; and last but not least – scalable architecture will allow you to run any number of jobs, and security configuration will be flexible enough to provide all kinds of access to end-users.

2018-05-03_9-47-51
Jenkins main page

Here are some of the tasks that can easily be achieved by using Jenkins instead of SQL Server Agent (and relevant examples):

  • Maintenance tasks across the whole environment: run your code on any number of servers with the help of Powershell and parametrized jobs.
    • Recurring backup-restore operations – achieved by using dbatools Powershell module.
    • Deploying scripts or database projects from source-controlled repositories – can be done with dbops Powershell module
    • Initiating failovers for planned maintenance operations – T-SQL or Powershell
  • Reports: invoke scripts, generate output files, send out notifications
    • Collect data from your servers using tools from Brent Ozar’s first responder kit and feed it into PowerBi reports
    • Run tests against your environment to ensure stability using dbachecks Powershell module
    • Running tSQLt tests against your development databases after deploying the code
    • Put together a notification email and send it to multiple groups of users
    • Notify admin about recent changes to the job that led to failure.
  • Chaining jobs together: jobs can trigger other jobs, wait for the child jobs to complete and aggregate the output.
    • Deploying code in multiple environments – one following another  – with the help of the dbops Powershell module
    • Setting up custom pipelines with manual or automatic approvals and notifications
    • Include database deployment as a part of application delivery pipeline
  • Working with artifacts: Jenkins will keep all the files and logs (called artifacts) produced by the task and grant the ability to view or download files in one click.
    • Keep execution logs and errors for an extended period
    • Publish report files
  • Interaction with other systems – any Jenkins control element can be called using a rich REST API
    • Trigger Jenkins jobs execution from SCM webhooks, Powershell or Python call
    • Retrieve job status information
    • Retrieve job artifacts using a simple web call
  • Integration with source code management systems: Git, SVN, TFS, you name it.
    • Deploy code by submitting commits to SCM
    • Run automated tests for your branches using multi-branch pipeline

Jenkins Setup

The installation steps are very simple:

  • Download latest Jenkins from the Jenkins website. You will be able to select between an installation package, Docker image or a simple jar file.
  • Start Jenkins using a method appropriate to a chosen distribution. More info here.
  • Go to http://localhost:8080/ and follow the instructions.

Jenkins Architecture

A simplified schema of Jenkins components might look like this:

2018-05-02_23-50-46
Top-level Jenkins design

Jenkins Master – your primary Jenkins server that keeps all the metadata, provides the interface and primary functions.

Jenkins Agents – Jenkins processes running on a computer that can be used to execute Jenkins jobs. Each Jenkins master has a built-in agent by default, but can easily be extended by adding more agents. Agents are communicating through network and can be configured to run as a certain OS user.

Executor – an execution space inside a Jenkins Agent that provides a single job queue to execute Jenkins jobs – one at a time.

Jenkins Job – a set of predefined activities executed one after another. A job execution attempt triggers a Build that can either fail or succeed and will contain relevant artifacts and logs. Each Build runs in a Workspace – dedicated working folder in Jenkins home directory.

2018-05-03_9-56-39
Jenkins has some really good-looking trend visualizations

Jenkins Plugins allow Jenkins to extend its capabilities by using free community-driven extensions. The extensions usually add new functionality or modify existing behavior. Actually, let’s talk more about Jenkins plugins, as they are an integral part of Jenkins setup.

Jenkins Plugins

One of the best reasons to use Jenkins is that, while it’s distributed with bare minimum of the components, its functionality can be (and should be) extended by picking from thousands of plugins coming from a huge Jenkins community. Actually, there are so many of them that sometimes it’s really confusing where to start. Here’s the list of plugins that I find very useful for all intents and purposes:

  • Active Directory – enables authentication through Active Directory
  • Blue Ocean – beautiful interface to build and control pipelines
  • Build Pipeline – adds a dashboard that can show jobs chained together into a build pipeline
  • Build Timeout – terminates the build after predefined amount of time
  • Conditional BuildStep – adds conditions to the job steps if necessary
  • Copy Artifact – copies artifacts from previous builds/other jobs
  • Email Extension – enhanced email experience
  • Folders – allows you to create folders for jobs
  • Git – integrates Jenkins with Git
  • Parametrized Trigger – allows to trigger jobs with parameters
  • Powershell – allows to run Powershell scripts or ad-hoc commands
  • Promoted Builds – promotes build status based on certain criteria and adds a possibility of manual interactions in the job chain (aka manual promotion)
  • Timestamper – adds timestamps to the log
  • Workspace Cleanup – allows to cleanup the workspace before/after build

Conclusion

Jenkins can become an important asset in your day-to-day work as a SQL Server professional and bring a whole new level of possibilities. However, it will only make sense to use it for a certain kind of tasks, which can be characterized as operating outside of SQL Server instance scope. It will not be able to completely replace the functionality and convenience of SQL Server Agent, yet in certain scenarios it can become your faithful ally.

PS

2018-05-03_1023
Who would win: SQL Server special Agent or one Jenkins boi

If I was asked, in which situations I would use Jenkins instead of Agent, the answer would probably be ‘it depends’, and it really does! I tried to come up with some kind of generic scenarios, in which one of the two tools will be a more logical choice based on my experience. However, these are only recommendations and, after all, there is always more than one right answer, so – feel free to experiment!

Scenario Tool of choice Comments
Execute SQL Server query SQLAgent Easy to setup and use
Execute OS command or a script Jenkins Better logging and troubleshooting, no dependencies on SQL Server, easily scalable
Run SSIS package SQLAgent Natively supported by Agent
Retrieve data from a single server SQLAgent A single Linked Server is easy to maintain
Retrieve data from multiple servers Jenkins Will take 1-2 lines of Powershell code instead of 20+ minimum in Agent; easily scales
Perform maintenance operation on a database SQLAgent Transact-SQL operations are handled perfectly from the SQL Server Agent
Perform maintenance operation on an instance/server/cluster/AG Jenkins No dependencies on SQL Server itself; can control status remotely
Execute SQL code from a remote source Jenkins Integration with SCM; plugins to control the behavior
Multi-step T-SQL job SQLAgent Has easily configurable order with actions on success/failure
Multi-step mixed language job Jenkins Easy to troubleshoot, more options, reliable
Trigger job on a SQL Server event SQLAgent Can use native tools (events or alarms), can be called from code
Trigger job on a remote application call Jenkins No permissions on SQL Server required, REST API, no DB connectivity needed