Many organizations use separate development, staging, and production environments to maintain the quality of their websites. Here’s how the environments look when ArcGIS Server is involved:
- Development—This is a sandbox ArcGIS Server site where you can freely test your applications and services. Typically, the development site runs on a small machine using an Esri Developer Network (EDN) license for ArcGIS Server. Once changes are validated on the development site, they are applied to the staging site.
- Staging—This ArcGIS Server site is a clone of the production site. Testing at this level results in a decision to apply the changes on the production site, or reject the changes and wait for a new iteration from the development site. The staging site is not used for development, just performance and functional testing. Esri provides staging licenses for ArcGIS Server users at a lower cost than production licenses.
- Production—This is the site that actually supports business workflows, the site accessed by real users. Absolutely no development or testing occurs on this site. Only changes that have passed the scrutiny of testing on the staging site are applied to the production site.
The development, staging, and production environments ideally use different databases and infrastructures. Each organization has its own rules for how changes are tested and approved across the sites.
Moving a change from site to site can present logistical challenges. This help topic provides patterns and scripts to guide you through the process.
Configuring each environment
In each environment, install ArcGIS Server, create a site, and configure security, server object extensions (SOEs), and other settings. Most of these tasks are faster if performed manually although you can use a script like Example: Create users and roles from two text files.
Get your development site working first and create the staging site, followed by the production site.
The key to deploying services in multiple environments is to register your folders and databases correctly with ArcGIS Server and use service definitions (SDs) for publishing.
Registering folders and databases with ArcGIS Server
When you register a folder or database with ArcGIS Server, you provide the publisher’s path to the data and the server’s path.
- The publisher’s path is the data path on the machine you’ll use to make the SD files. The publisher’s path is always the same when you register an item on the development, staging, and production servers.
- The server’s path is the data path on the server. This path can vary when you register an item on the development, staging, and production servers.
If you have many data folders or databases to register, you may consider using scripts. Example: Register folders and databases listed in a text file uses the ArcPy AddDataStoreItem function to register a list of folders and database connections supplied in a text file. You modify the text file for each environment.
Use SD files when deploying your services in multiple environments. The SD takes the information needed to publish a service and packages it into one convenient file. Although it’s possible to package the GIS data within the SD, you’ll probably find it easier to preload the data in each environment and use replication to keep it in sync.
Create connection-neutral SD files (choose the No available connection option in the Save a Service Definition wizard) so they are flexible enough to be published on any server. When you publish an SD file, ArcGIS Server automatically corrects the paths written in the SD so that your server paths are used. Careful data registration allows you to deploy the same SD file in multiple environments.
Publishing services is a task well-suited for scripting. Example: Publish service definitions listed in a text file reads a text file and publishes all SDs listed. The script uses the ArcPy function Upload Service Definition to publish each SD.
After deploying your services from the SDs, enable any extensions required by the services. This can be done manually or through scripting.
Applying permissions is another task that can be scripted. Example: Apply permissions from a text file uses the ArcGIS REST API to apply permissions to various services as listed in a text file.
Sometimes you might want to update a service to use new properties or reflect changes in the source document, such as a set of permanent symbology edits in an ArcMap document (MXD). The recommended way to update a service in multiple environments is to save a new SD file, delete the service, then publish the updated SD.
When you take this approach, the same example script used above for publishing can also perform service updates. Just modify the input file to include only the services you want to update. If an existing service is found, the script deletes it before uploading the SD.
After you update a service in this way, reenable any SOEs used by the service.
You can alternatively script updates to service properties (but not the map or source document) using the Edit Service operation in the ArcGIS REST API.
Keeping data in sync
Ensure your data is kept in sync across your multiple environments. Geodatabase replication can help you with this. Alternatively, you can completely replace the old dataset with a new dataset. For example, you might delete a file geodatabase and replace it with an updated file geodatabase.
If you decide to entirely replace tables or file geodatabases, remember that ArcGIS Server services lock the schemas of the underlying datasets by default. If the schema is locked, stop your service before you can replace the data. With some degree of caution you can disable schema locking for map services, but you can’t disable it for other service types.
To move an application between the development, staging, and production environments, copy the application files from one site to the other and update any web service URLs in your code so they point at the new site. Use configuration files to define the URLs for your services.
The script below helps you update the URLs in your code. The code recursively looks for files within a folder you provide, searches for a particular string such as http://myDevServer/arcgis, and replaces it with the location of your staging or production site, such as http://myProdServer/arcgis.
Once you’ve replaced the URLs using the script, copy the application files onto the next server in the workflow (staging or production).
import os import sys import shutil import traceback def dirEntries(dir_name, subdir, *args): '''Return a list of file names found in directory 'dir_name' If 'subdir' is True, recursively access subdirectories under 'dir_name'. Additional arguments, if any, are file extensions to match filenames. Matched file names are added to the list. If there are no additional arguments, all files found in the directory are added to the list. Example usage: fileList = dirEntries(r'H:\TEMP', False, 'txt', 'py') Only files with 'txt' and 'py' extensions will be added to the list. Example usage: fileList = dirEntries(r'H:\TEMP', True) All files and all the files in subdirectories under H:\TEMP will be added to the list. ''' fileList =  for file in os.listdir(dir_name): dirfile = os.path.join(dir_name, file) if os.path.isfile(dirfile): if not args: fileList.append(dirfile) else: if os.path.splitext(dirfile)[1:] in args: fileList.append(dirfile) # recursively access file names in subdirectories elif os.path.isdir(dirfile) and subdir: print "Accessing directory:", dirfile fileList.extend(dirEntries(dirfile, subdir, *args)) return fileList def updateString(infileName, srchString,rplString): bakFileName = os.path.splitext(infileName) + ".bak" if not os.path.exists(bakFileName): # copy the original file shutil.copy(infileName, bakFileName) # Open the backup (= original) file to read inFileHndl = open(bakFileName,"r") outFileHndl = open(infileName,"w") for line in inFileHndl: if line.find(searchString) > 0: line = line.replace(searchString, replaceString) outFileHndl.write(line) outFileHndl.close() inFileHndl.close() # remove the backup (=original content file) os.remove(bakFileName) if __name__ == '__main__': try: inFolder = r"C:\inetpub\wwwroot\viewer" # path to search searchString = "http://mydevserver" # string to find replaceString = "http://mystgserver" # string - replace searchString with replaceString fList = dirEntries(inFolder, True, 'xml') for f in fList: updateString(f, searchString, replaceString) print '\n\n\n' + 'Process Complete' except: # Return any python specific errors as well as any errors from the geoprocessor # tb = sys.exc_info() tbinfo = traceback.format_tb(tb) pymsg = "PYTHON ERRORS:\nTraceback Info:\n" + tbinfo + "\nError Info:\n " + \ str(sys.exc_type)+ ": " + str(sys.exc_value) + "\n" print '\n\n\n' + pymsg