AGS admin scripting help

6086
24
Jump to solution
07-28-2016 06:15 AM
JamesCrandall
MVP Frequent Contributor


I'm trying to build some simple service checks (map, feature and gp services) that are published on our ArcGIS Server site(s). Example: Check a folder for stopped services—Documentation (10.3 and 10.3.1) | ArcGIS for Server is what I'm attempting to implement but having difficulty with the request at fetching the token.

I've been provided with the serverName and serverPort parameters (lines 22 and 23 of the sample code) by our AGS admin but I keep tripping the error at line 137.  If I print the response.status it shows a response of 302 and response.reason is "Found".

Any input or success implementing this script?

0 Kudos
24 Replies
RebeccaStrauch__GISP
MVP Emeritus

Kevin,

re: the .AGS file.  I thought there were other "tools" that could use this as input already. Not necessarily pure Python code, by maybe arcpy code??  I'll have to look to see if I can find any samples, or things that maybe I have used.

Kevin Hibma  re: the filter.  When you startup ArcGIS Server, it does remember what was started when you shut AGS, so that information is stored somewhere.  But obviously I'm not necessarily wanting to shut the AGS site down just to replace the source for these dozen or so services.  BTW - because my process recreates a FGDB and derived datasets each time (from a master SDE database), I can't use replicate and need to replace it each time.

I'll have to work on the filter part myself I think....

  • maybe use a inventory of all data sources withing all the .mxds being used by the services, search for the \\machinename\fgdbpath and/or d:\fgdbpath in that inventory.  Write a list of all these folders\services
  • then use something like the sample on Manage Service utility—Documentation (10.4) | ArcGIS for Server  page to find all the the STARTED services
The following example lists all the services in the site.
<Python installation location>\python.exe "C:\Program Files\ArcGIS\Server\tools\admin\manageservice.py" -u admin -p admin -s http://gisserver.domain.com:6080 -l 

and it looks like the the key here is the

-l Lists the services on the GIS server and displays whether they are stopped or started.

or use Example: Check a folder for stopped services—Documentation (10.4) | ArcGIS for Server   but change it to STARTED instead of STOPPED (??).  anyway, if I can just check those in the list I created, and updating the list for those that are currently STARTED

  • run the stop against my filtered list
  • rename/replace....
  • run the start on same filtered list

I'm still looking around to see if anyone has already put a workflow like this together, but I think I'm going to have to write it myself.  But again, the real snag here are the admin credentials.  This is all part of a python addin toolbar, and not something I want to hardcode into my addin.  This addin does take advantage of an .SDE connection file already, so being able to do the same with the .AGS connection file would be ideal.

So, I'm open to any suggestions re: getting the credentials input without exposing the info in the script, addin, or results tab (or anything that can grab the clear-text info).  Thanks much for the tools so far....I have used them often (just a pain to have to manually figure out my filtering..and of course the user/pass issue.

btw - my sincere apologies James Crandall for hijacking the thread, but hopefully this is something you are interested in too.

0 Kudos
KevinHibma
Esri Regular Contributor

There are some tools/functions that make use of .AGS files. There is a big difference between "those tools" and the tools in the Administration toolkit. The built-in, system tools have access to all the internal workings of ArcGIS. The tools I've written in Python dont have the same level of 'arcgis' access. Simply put, the tools I wrote dont rely on ArcGIS/arcpy, and even if they did, they couldn't make use of a .AGS file to accomplish the end goal of 'administrative tasks' on the server. Those 'hooks' are not exposed in the software to 'python developers'.

You're right about the stopped|started information being held somewhere. However the interaction with the tools and the server itself is very short lived. The tools only are aware and talk to the server during their execution. As such, any tool or script needs to get all the information from the server and perform the action during that session. So the tools I wrote would need to query the server, get that information, and then perform an appropriate action. The LIST script you reference is essentially the same code I have in the STOP | START | DELETE tool. This action of getting the services and their state needs to happen each time the tool is run.

The idea James offers below is a great method of hiding credentials from plain view. It isn't 100% secure (really any solution that requires you to save credentials on the client machine isn't secure). But its better plain text!

JamesCrandall
MVP Frequent Contributor

This looks like a really comprehensive tool set!  But it's a bit much for what we need I think.  To go from just running a simple script to check what services are stopped/running to this is pretty extreme.

I'm not sure why the example script doesn't play nice with https.  Seems like something do-able to overcome.

0 Kudos
JamesCrandall
MVP Frequent Contributor

No problem, hijack away!

Here's an idea to keeping credentials out of things.  Well, sort of.

You could just setup a simple .ini file to hold any credentials and then use base64 library in the python scritping.  It's not a 100% secure approach, but it'd keep any hardcoded credentials out of the codebase and some low-level secuity using base64 to encode/decode that will essentially hide any variable values from view that might be set.  Like so:

*** create a "settings.ini" file and save it in the same directory as the .py script
[AGS]
USER = someusername
PASS = somepassword

The implement base64 and ConfigPaser in your .py scripting:

import ConfigParser
import base64
# Find and gather settings from the settings.ini file
localPath = sys.path[0]
settingsFile = os.path.join(localPath, "settings.ini")
config = ConfigParser.ConfigParser()
config.read(settingsFile)

# Get encoded credentials
uname_encoded = base64.b64encode(config.get( 'AGS', 'USER'))
pwd_encoded = base64.b64encode(config.get('AGS', 'PASS'))

# use the encoded credentials for any login parameters
# for example, build the URL with credentials for the REST API
agsurl = 'https://yourAGSaddress'
site = '/arcgis'
URL = agsurl + site + "/rest/services"
      
# obtain a token  
referer = agsurl
query_dict = { 'username': base64.b64decode(uname_encoded), 'password': base64.b64decode(pwd_encoded), 'referer': referer }  
query_string = urllib.urlencode(query_dict)
url = agsurl + site + "/tokens/generateToken"
token = json.loads(urllib.urlopen(url + "?f=json", query_string).read()) 

#...blah blah blah you get the idea
KevinHibma
Esri Regular Contributor

This is a great suggestion. Having user/password saved in plain text is just bad form. And sadly, I've encouraged that in places (GitHub - arcpy/update-hosted-feature-service: Update and overwrite a hosted feature service on ArcGI... ) Maybe I'll try to update that sample with your approach. And, yes, its still very possible for someone to find out the credentials. However, any sort of security is better than no security. Thanks, James.

RebeccaStrauch__GISP
MVP Emeritus

Hi Kevin Hibma ,

I'm making (slow) progress using the sample James Crandall provided above (Many thanks for that James!)

Quick (?) question(s)...

I was looking at the samples for ListingMapServices ArcGIS Help (10.2, 10.2.1, and 10.2.2)  but only seems to pass the "unsecure" services, even if I pass the token.  Your "Stop, Start, Delete services" will list them all, but is not filtered for those that are STARTED.

  • How can I get a script to return all of the services (secured or not), but filtered for only those that are STARTED?  Kind of a combo of the above....but also almost opposite of both.
  • I might have better luck once I have it as a tool, but I'm still testing as snippets in the python window

Again, long term goal (simplified)...stop only those services that are accessing the FGDB that I need to update..replace the FGDB...then start just those back up.  All while keeping credentials secure.  Simple...right.  lol.    I may need to look at the link James had at the beginning of the thread to see if I can do the opposite of what it is supposed to do.

On that same "secure" thought....is there anyway to block things being written to the results table....or to programatically remove entries from the script?   did decide that rather than using the "agsurl " as shown in James' script, if I use the local server name and port 6080, that should prevent access from outside the network (and thinking maybe a local server account??).

0 Kudos
SubuSwaminathan1
Occasional Contributor

I agree with Rebecca that being able to hide/encrypt or encapsulate the admin user credentials in a secure fashion is the most important piece that is missing. Once that is in place, being able to able to access secured services, https, service status and all others all become more useful. In fact looking at the this thread and the contributions, most of the rest has been achieved and folks are willing to share with the community.

Thanks

Subu

0 Kudos
RebeccaStrauch__GISP
MVP Emeritus

Subu, I actually have a script that works now using the suggestiin from James Crandall to use an ini file to create a token, and some of the admin tool items that Kevin Hibma​ has been working....although I've simplified for my needs. I have it so I can select the services I want to stop/start, based on whether they access a particular fgdb.  That part all seems to work.  I'm planning on posting once I have it in a more generic format.  It needs some cleanup and documentation etc.  also, I still need to make sure that once run in a tool, it doesn't capture the user credentials anywhere.

0 Kudos
by Anonymous User
Not applicable

Hi

i am using current version of AGS admin tool with the help of this tool I am to list down all stop services without error.

and also create one Python script to generate reports of all map services.
if you require then i will share with you.

thanks.

0 Kudos
JamesCrandall
MVP Frequent Contributor

We just have a simple need to check services to see STOPPED/STARTED status --- that's really it.  Couple of reasons why:

1.  To build a dashboard that can be displayed on a monitor hanging on the wall.  Pretty simple .aspx page or something like that showing Red & Green for stopped/started services.

2.  We have applications developed with the JavaScript API that other departments within the organization build and these utilize our ArcGIS Server services (map, feature & GP services).  With the simple code below we published as a GP service that those applications can check against to see status and handle the appropriate methods if at runtime of their application it experiences a stopped service.  Again, pretty simple yet has a lot of value.

Part of the GP service that checks service status:

def reviewRunning(token):

    query_dict = { "f": "json", "token": token['token'] }  

    # query your services url  
    jsonResponse = urllib.urlopen(URL, urllib.urlencode(query_dict))
    rooturl = agsurl + site + "/admin/services"
    rootresp = json.loads(urllib.urlopen(rooturl + "?f=json", urllib.urlencode(query_dict)).read())
    fldrs = rootresp['folders']
    for fldr in fldrs:
       fldrurl = agsurl + site + "/admin/services/" + fldr  

       query_dict = { "f": "json", "token": token['token'] }   
       svcresp = json.loads(urllib.urlopen(fldrurl + "?f=json", urllib.urlencode(query_dict)).read())
       svcs = svcresp['services']
       for svc in svcs:
           svcname = svc['serviceName']
           svctype = svc['type']

           query_dict = { "f": "json", "token": token['token'] }

           svcstatusurl =  fldrurl + "/" + svcname + "." + svctype + "/status"
           svcstatusresp = json.loads(urllib.urlopen(svcstatusurl + "?f=json", urllib.urlencode(query_dict)).read())

           svcstatus = svcstatusresp['realTimeState']
           print svcname, svctype, svcstatus
0 Kudos