I'm trying to run a python scrtipt to stop services, but I'm getting the following error message : "No JSON object could be decoded" . My server uses https protocol thru port 6443. I'm using the file "StartStopServices.py" available at following path: https://github.com/WestonSF/ArcGISAdminToolkit/commit/a183df77441956e515105b2b166b11eb4e525873
#-------------------------------------------------------------
# Name: Start or Stop Services
# Purpose: Starts or stops GIS services. Can start/stop all GIS services for an ArcGIS server site or just the ones
# that are specified.
# Author: Shaun Weston (shaun_weston@eagle.co.nz)
# Date Created: 07/10/2014
# Last Updated: 06/11/2014
# Copyright: (c) Eagle Technology
# ArcGIS Version: 10.1+
# Python Version: 2.7
#--------------------------------
# Import modules
import os
import sys
import logging
import smtplib
import arcpy
import httplib
import json
import urllib
import urllib2
import urlparse
# Enable data to be overwritten
arcpy.env.overwriteOutput = True
# Set global variables
enableLogging = "false" # Use logger.info("Example..."), logger.warning("Example..."), logger.error("Example...")
logFile = "" # os.path.join(os.path.dirname(__file__), "Example.log")
sendErrorEmail = "false"
emailTo = ""
emailUser = ""
emailPassword = ""
emailSubject = ""
emailMessage = ""
output = None
# Start of main function
def mainFunction(agsServerSite,username,password,startStop,allServices,userServices): # Get parameters from ArcGIS Desktop tool by seperating by comma e.g. (var1 is 1st parameter,var2 is 2nd parameter,var3 is 3rd parameter)
try:
# Logging
if (enableLogging == "true"):
# Setup logging
logger, logMessage = setLogging(logFile)
# Log start of process
logger.info("Process started.")
# --------------------------------------- Start of code --------------------------------------- #
# Get the server site details
protocol, serverName, serverPort, context = splitSiteURL(agsServerSite)
# If any of the variables are blank
if (serverName == None or serverPort == None or protocol == None or context == None):
return -1
# Add on slash to context if necessary
if not context.endswith('/'):
context += '/'
# Add on admin to context if necessary
if not context.endswith('admin/'):
context += 'admin/'
# Get token
token = getToken(username, password, serverName, serverPort)
# If token received
if (token != -1):
services = []
folder = ''
# If task is for all services
if (allServices == "true"):
# Query the root level for services
url = "http://{}:{}/arcgis/admin/services{}?f=pjson&token={}".format(serverName, serverPort, folder, token)
# Make the request
try:
serviceList = json.loads(urllib2.urlopen(url).read())
except urllib2.URLError, error:
arcpy.AddError(error)
# Logging
if (enableLogging == "true"):
logger.error(error)
sys.exit()
# Add the services at the root level
for single in serviceList["services"]:
services.append(single['serviceName'] + '.' + single['type'])
# Build up list of folders and remove the System and Utilities folder
folderList = serviceList["folders"]
folderList.remove("Utilities")
folderList.remove("System")
# If there is any folders
if len(folderList) > 0:
# For each folder in the list
for folder in folderList:
# Query the folder for map services
URL = "http://{}:{}/arcgis/admin/services/{}?f=pjson&token={}".format(serverName, serverPort, folder, token)
fList = json.loads(urllib2.urlopen(URL).read())
for single in fList["services"]:
# Add the services found to the list
services.append(folder + "/" + single['serviceName'] + '.' + single['type'])
# Just for the user defined list of services
else:
services = userServices.split(",")
# For each of the services
for service in services:
# Start or stop the map service
op_service_url = "http://{}:{}/arcgis/admin/services/{}/{}?token={}&f=json".format(serverName, serverPort, service, startStop, token)
status = urllib2.urlopen(op_service_url, ' ').read()
# If successfully started/stopped
if 'success' in status:
arcpy.AddMessage(startStop + " successfully performed on " + service)
# Logging
if (enableLogging == "true"):
logger.error(startStop + " successfully performed on " + service)
# If there is an error
else:
arcpy.AddError("Failed to perform operation. Returned message from the server:")
arcpy.AddError(status)
# Logging
if (enableLogging == "true"):
logger.error("Failed to perform operation. Returned message from the server:")
logger.error(status)
# --------------------------------------- End of code --------------------------------------- #
# If called from gp tool return the arcpy parameter
if __name__ == '__main__':
# Return the output if there is any
if output:
arcpy.SetParameterAsText(1, output)
# Otherwise return the result
else:
# Return the output if there is any
if output:
return output
# Logging
if (enableLogging == "true"):
# Log end of process
logger.info("Process ended.")
# Remove file handler and close log file
logging.FileHandler.close(logMessage)
logger.removeHandler(logMessage)
pass
# If arcpy error
except arcpy.ExecuteError:
# Build and show the error message
errorMessage = arcpy.GetMessages(2)
arcpy.AddError(errorMessage)
# Logging
if (enableLogging == "true"):
# Log error
logger.error(errorMessage)
# Remove file handler and close log file
logging.FileHandler.close(logMessage)
logger.removeHandler(logMessage)
if (sendErrorEmail == "true"):
# Send email
sendEmail(errorMessage)
# If python error
except Exception as e:
errorMessage = ""
# Build and show the error message
for i in range(len(e.args)):
if (i == 0):
errorMessage = unicode(e.args[i]).encode('utf-8')
else:
errorMessage = errorMessage + " " + unicode(e.args[i]).encode('utf-8')
arcpy.AddError(errorMessage)
# Logging
if (enableLogging == "true"):
# Log error
logger.error(errorMessage)
# Remove file handler and close log file
logging.FileHandler.close(logMessage)
logger.removeHandler(logMessage)
if (sendErrorEmail == "true"):
# Send email
sendEmail(errorMessage)
# End of main function
# Start of get token function
def getToken(username, password, serverName, serverPort):
query_dict = {'username': username,
'password': password,
'expiration': "60",
'client': 'requestip'}
query_string = urllib.urlencode(query_dict)
url = "http://{}:{}/arcgis/admin/generateToken?f=json".format(serverName, serverPort)
try:
token = json.loads(urllib2.urlopen(url, query_string).read())
if "token" not in token or token == None:
arcpy.AddError("Failed to get token, return message from server:")
arcpy.AddError(token['messages'])
# Logging
if (enableLogging == "true"):
logger.error("Failed to get token, return message from server:")
logger.error(token['messages'])
sys.exit()
else:
# Return the token to the function which called for it
return token['token']
except urllib2.URLError, error:
arcpy.AddError("Could not connect to machine {} on port {}".format(serverName, serverPort))
arcpy.AddError(error)
# Logging
if (enableLogging == "true"):
logger.error("Could not connect to machine {} on port {}".format(serverName, serverPort))
logger.error(error)
sys.exit()
# End of get token function
# Start of HTTP POST request to the server function
def postToServer(serverName, serverPort, protocol, url, params):
# If on standard port
if (serverPort == -1 and protocol == 'http'):
serverPort = 80
# If on secure port
if (serverPort == -1 and protocol == 'https'):
serverPort = 6443
if (protocol == 'http'):
httpConn = httplib.HTTPConnection(serverName, int(serverPort))
if (protocol == 'https'):
httpConn = httplib.HTTPSConnection(serverName, int(serverPort))
headers = {"Content-type": "application/x-www-form-urlencoded", "Accept": "text/plain",'referer':'backuputility','referrer':'backuputility'}
# 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
return (response, data)
# End of HTTP POST request to the server function
# Start of split URL function
def splitSiteURL(siteURL):
try:
serverName = ''
serverPort = -1
protocol = 'http'
context = '/arcgis'
# Split up the URL provided
urllist = urlparse.urlsplit(siteURL)
# Put the URL list into a dictionary
d = urllist._asdict()
# Get the server name and port
serverNameAndPort = d['netloc'].split(":")
# User did not enter the port number, so we return -1
if (len(serverNameAndPort) == 1):
serverName = serverNameAndPort[0]
else:
if (len(serverNameAndPort) == 2):
serverName = serverNameAndPort[0]
serverPort = serverNameAndPort[1]
# Get protocol
if (d['scheme'] is not ''):
protocol = d['scheme']
# Get path
if (d['path'] is not '/' and d['path'] is not ''):
context = d['path']
# Return variables
return protocol, serverName, serverPort, context
except:
arcpy.AddError("The ArcGIS Server site URL should be in the format http(s)://<host>:<port>/arcgis")
# Logging
if (enableLogging == "true"):
logger.error("The ArcGIS Server site URL should be in the format http(s)://<host>:<port>/arcgis")
sys.exit()
return None, None, None, None
# End of split URL function
# Start of status check JSON object function
def assertJsonSuccess(data):
obj = json.loads(data)
if 'status' in obj and obj['status'] == "error":
if ('messages' in obj):
errMsgs = obj['messages']
for errMsg in errMsgs:
arcpy.AddError(errMsg)
# Logging
if (enableLogging == "true"):
logger.error(errMsg)
sys.exit()
return False
else:
return True
# End of status check JSON object function
# Start of set logging function
def setLogging(logFile):
# Create a logger
logger = logging.getLogger(os.path.basename(__file__))
logger.setLevel(logging.DEBUG)
# Setup log message handler
logMessage = logging.FileHandler(logFile)
# Setup the log formatting
logFormat = logging.Formatter("%(asctime)s: %(levelname)s - %(message)s", "%d/%m/%Y - %H:%M:%S")
# Add formatter to log message handler
logMessage.setFormatter(logFormat)
# Add log message handler to logger
logger.addHandler(logMessage)
return logger, logMessage
# End of set logging function
# Start of send email function
def sendEmail(message):
# Send an email
arcpy.AddMessage("Sending email...")
# Server and port information
smtpServer = smtplib.SMTP("smtp.gmail.com",587)
smtpServer.ehlo()
smtpServer.starttls()
smtpServer.ehlo
# Login with sender email address and password
smtpServer.login(emailUser, emailPassword)
# Email content
header = 'To:' + emailTo + '\n' + 'From: ' + emailUser + '\n' + 'Subject:' + emailSubject + '\n'
body = header + '\n' + emailMessage + '\n' + '\n' + message
# Send the email and close the connection
smtpServer.sendmail(emailUser, emailTo, body)
# End of send email function
# This test allows the script to be used from the operating
# system command prompt (stand-alone), in a Python IDE,
# as a geoprocessing script tool, or as a module imported in
# another script
if __name__ == '__main__':
# Arguments are optional - If running from ArcGIS Desktop tool, parameters will be loaded into *argv
argv = tuple(arcpy.GetParameterAsText(i)
for i in range(arcpy.GetArgumentCount()))
mainFunction(*argv)
That's definitely JSON, so I'm not sure why the error is being thrown. The thing I haven't seen before is how you're constructing the parameters for the getToken request.
url = "https://{}:{}/arcgis/admin/generateToken?f=json".format(server, port)
query_dict = {
'username': adminUser,
'password': adminPass,
'expiration': str(expiration),
'client': 'requestip'
}
f=json is a parameter sent along with the request, so it should be included in the query_dict:
url = "https://{}:{}/arcgis/admin/generateToken".format(server, port)
query_dict = {
'username': adminUser,
'password': adminPass,
'expiration': str(expiration),
'client': 'requestip',
'f':'json'
}
What if you give that a try?
Jonathan,
Thanks for the suggestion. When I tested this out, I was still getting the same error. However, I was able to successfully run this script by updating lines 56-57 a little:
try:
# Request the token
with contextlib.closing(urllib2.urlopen(url, query_string)) as jsonResponse:
response = jsonResponse.read()
print response
getTokenResult = json.loads(response)
Craig
Hm, not sure why turning the string to a JSON object couldn't be done in one line, but glad it's working now!