Skip To Content

示例:发布文本文件中列出的服务定义

本示例脚本从服务定义文件 (SD) 的文本文件列表进行读取,并将各 SD 作为服务发布。如果要在实验室的多台计算机上部署相同的服务集,或者要跨开发、过渡和生产服务器进行部署,这一功能将非常有用。

输入文件应具有如下所示的结构:

#SD|folderName|serviceName
SD=\\mylabserver\Yellowstone.sd|folderName=Parks|serviceName=Yellowstone
SD=\\mylabserver\Rainier.sd|serviceName=Rainier
SD=C:\data\BufferGP.sd|serviceName=BufferGeoprocessing
SD=C:\data\Arches.sd|folderName=Parks|serviceName=Arches

  • SD - 服务定义文件的路径。该位置必须对 ArcGIS Server 可见,但并不需要注册到 ArcGIS Server。
  • folderName - 应包含上述服务的 ArcGIS Server 文件夹名称。该文件夹必须已经存在。如果忽略该属性,则上述服务将在根级别发布。
  • serviceName - 服务的名称(如果要覆盖 SD 中的名称)。

脚本首先检查指定文件夹中是否存在该服务。如果该服务已存在,则将被删除,然后重新发布。因此,该文本文件可以包含一长串要部署的服务,也可以仅包含一个要更新的服务。

import json
import urllib,httplib
import sys
import getpass
import arcpy
import os
import codecs
def main(argv=None):
    
    # Ask for admin user name and password
    
    username = raw_input("Enter user name: ")
    password = getpass.getpass("Enter password: ")
    
    # Ask for server name and the port
    serverName = raw_input("Enter server name: ")
    serverPort = raw_input("Enter server port: ")
    
    # Get a token and connect
    token = getToken(username, password, serverName, serverPort)
    
    if token == "":
        sys.exit(1)
    # Create a connection file to the server            
    serverURL="http://"+serverName+":"+str(serverPort)+"/arcgis/admin"
    try:
        arcpy.mapping.CreateGISServerConnectionFile("PUBLISH_GIS_SERVICES",os.curdir,serverName+".ags",serverURL,"ARCGIS_SERVER",username=username,password=password)
    except Exception, e:
            print e.message   
    
    agsConnection = os.path.join(os.curdir, serverName+".ags")
    
    if not os.path.isfile(agsConnection):
        print("Unable to connect to ArcGIS Server -- exiting")
        sys.exit(1)
    
    # Input file that contains the services information
    servicesFile = raw_input("Path to pipe-delimited text file containing services: ")
    
    num = 0 
    services = {}
    
    for serviceRow in readlinesFromInputFile(servicesFile):
        
        serviceEntry = {}
            
        for index in range(len(serviceRow)):
            
            serviceProp = serviceRow[index].split("=")
            
            if serviceProp[0] == "SD":
                serviceEntry["in_sd_file"] = serviceProp[1]
            if serviceProp[0] == "serviceName":
                serviceEntry["in_service_name"] = serviceProp[1]
            if serviceProp[0] == "folderName":
                serviceEntry["in_folder"] = serviceProp[1]
                if isFolderPresent(serviceProp[1],serverName, serverPort,token):
                    serviceEntry["in_folder_type"]="EXISTING"
                else:        
                    serviceEntry["in_folder_type"]="NEW"
            if serviceProp[0] == "startupType":
                serviceEntry["in_startupType"] = serviceProp[1]
         
            # Add the services information to a dictionary
            services["service" + str(num)] = serviceEntry
        num +=1
        
    # Call helper functions to publish services
    addServices(services,serverName,serverPort,token,agsConnection)
# A function that reads lines from the input file
def readlinesFromInputFile(filename, delim='|'):
    file = codecs.open(filename,'r','utf-8-sig')
    for line in file.readlines():
        # Remove the trailing whitespaces and the newline characters
        line = line.rstrip()
        
        if line.startswith('#') or len(line) == 0:
            pass # Skip the lines that contain # at the beginning or any empty lines
        else:
            # Split the current line into list
            yield line.split(delim)
    file.close()
    
def addServices(serviceDict, serverName, serverPort, token, agsConnection):
    
    for serviceToAdd in serviceDict:
        
        # Check to see that SD is present and that it is reachable.
        if not os.path.isfile(serviceDict[serviceToAdd]['in_sd_file']):
            print("Unable to access '" + serviceDict[serviceToAdd]['in_sd_file']+"'. Skipping to publish.")
       
        else:    
            #Delete the service first (if it exists) and then re-publish it
            if serviceDict[serviceToAdd].has_key("in_service_name"):
                if serviceDict[serviceToAdd].has_key("in_folder"):
                    deleteServiceIfPresent(serverName,serverPort,token,serviceDict[serviceToAdd]["in_service_name"],serviceDict[serviceToAdd]["in_folder"])
                else:
                    deleteServiceIfPresent(serverName,serverPort,token,serviceDict[serviceToAdd]["in_service_name"])
                        
            serviceDict[serviceToAdd]["in_server"] =  agsConnection
            
            print "Publishing the service: " + serviceDict[serviceToAdd]['in_sd_file']
            
            try:
                arcpy.UploadServiceDefinition_server(**serviceDict[serviceToAdd])
                print "Successfully published the service: " + serviceDict[serviceToAdd]['in_sd_file']
                
            except Exception, e:
                print "Publishing of " + serviceDict[serviceToAdd]['in_sd_file'] + " failed."
                print e.message
 
# A function that will post HTTP POST request to the server
def postToServer(serverName, serverPort, url, params):
    
    httpConn = httplib.HTTPConnection(serverName, serverPort)
    headers = {"Content-type": "application/x-www-form-urlencoded", "Accept": "text/plain"}
    # URL encode the resource URL
    url = urllib.quote(url.encode('utf-8'))
    
    # Build the connection to add the roles to the server
    httpConn.request("POST", url, params, headers)
    response = httpConn.getresponse()
    data = response.read()
    httpConn.close()
    return (response, data)
    
# A function that checks that the JSON response received from the server does not contain an error   
def assertJsonSuccess(data):
    obj = json.loads(data)
    if 'status' in obj and obj['status'] == "error":
        return False
    else:
        return True
def getToken(username, password, serverName, serverPort):
    tokenURL = "/arcgis/admin/generateToken"
    params = urllib.urlencode({'username': username, 'password': password,'client': 'requestip', 'f': 'json'})
    
    response, data = postToServer(serverName, serverPort, tokenURL, params)
        
    if (response.status != 200 or not assertJsonSuccess(data)):
        print "Error while fetching tokens from admin URL. Please check if the server is running and ensure that the username/password provided are correct"
        print str(data)
        return
    else: 
        # Extract the token from it
        token = json.loads(data)   
        return token['token']            
    
def isFolderPresent(folderName,serverName, serverPort,token):
    
    params = urllib.urlencode({'token':token,'f': 'json'})    
    folderURL = "/arcgis/admin/services"
    
    response, data = postToServer(serverName, serverPort, folderURL, params)
        
    if (response.status != 200 or not assertJsonSuccess(data)):
        print "Error while fetching folders from the server."
        print str(data)
        return
    
    servicesJSON = json.loads(data)
    
    folders = servicesJSON['folders']
    for folder in folders:
        if folder == folderName :
            return True
    return False      
    
def deleteServiceIfPresent(serverName,serverPort, token, serviceName, folderName='root'):
    
    # If the folder itself is not present, we do not need to check for the service's presence in this folder.
    if folderName != 'root' and not isFolderPresent(folderName,serverName, serverPort,token): 
            return
            
    params = urllib.urlencode({'token':token,'f': 'json'})
        
    if  folderName == 'root' :
        URL = "/arcgis/admin/services/"
    else:
        URL = "/arcgis/admin/services/"+folderName
    
    response, data = postToServer(serverName, serverPort, URL, params)
        
    if (response.status != 200 or not assertJsonSuccess(data)):
        print "Error while fetching the service information from the server."
        print str(data)
        return
        
    #extract the services from the JSON response
    servicesJSON = json.loads(data)
    
    services = servicesJSON['services']
    for service in services:
        if service['serviceName'] == serviceName : 
            
            ##delete the service
            params = urllib.urlencode({'token':token,'f': 'json'})
            if  folderName == 'root' :
                URL = "/arcgis/admin/services/"+serviceName+"."+service['type']+"/delete"
            else:
                URL = "/arcgis/admin/services/"+ folderName + "/" + serviceName+"."+service['type']+"/delete"
            
            print "Found the service '" + serviceName + "."+ service['type'] + " at '" + folderName + "' folder in the server, the service will be deleted and be re-published."
           
            response, data = postToServer(serverName, serverPort, URL, params)
            
            if (response.status != 200 or not assertJsonSuccess(data)):
                
                print "Failed to delete the service: '" + serviceName + "." + service['type']
                print str(data)
                return
            else:
                print "Deleted the service '" + serviceName + "."+service['type']+ " successfully."
    
# Script start 
if __name__ == "__main__":
    sys.exit(main(sys.argv[1:]))