publish a referenced feature service from arcgis pro to arcgis enterprise using python

1263
4
Jump to solution
05-04-2021 02:18 PM
AzinSharaf
Occasional Contributor II

I need to publish a feature service using python from an arcgis pro map to arcgis enterprise (with a federated server). The feature service should be referenced to enterprise geodatabase (not hosted).
I’ve written a script with the following steps/logic but at the end it doesn’t give me what I need. Do you suggest a better solution?

( this is not the code,  just the logic. I can share it if it is needed.)

 

 

-	Publish map service:
o	Sign in to the portal (arcpy.SignInToPortal)
o	Create a sharing draft form arcgis pro map:
o	sharing_draft = m.getWebLayerSharingDraft(server_type="FEDERATED_SERVER", service_type="MAP_IMAGE", service_name=service)
o	Export to SD Draft: sharing_draft.exportToSDDraft(sddraft_output_filename)
o	Staging: arcpy.server.StageService(in_service_definition_draft=sddraft_output_filename, out_service_definition=sd_output_filename)
o	arcpy.server.UploadServiceDefinition
-	Enable Feature Access:
o	Connect to service api with arcgis Rest API and change the json file:
o	response = requests.post(service_url, data=params, verify=True)
o	data = response.json()
o	data['extensions'][i]['enabled'] = 'true'
o	updated_svc_json = json.dumps(data)
o	edit_svc_url = service_url + "/edit"
o	params = {'token': token, 'f': 'pjson', 'service': updated_svc_json}
o	response = requests.post(edit_svc_url, data=params, verify=True)

 

The script publishes map service from arcgis pro map, referencing to enterprise geodatabase (not hosted), enables the feature access BUT since the server is federated with the portal the script DOESN’T create feature layer item in portal which is the missing part in my workflow. Please advise.

 

0 Kudos
1 Solution

Accepted Solutions
AzinSharaf
Occasional Contributor II

I was able to finish the script. I am sharing it here in case you have same question.

import os
import arcpy
from arcgis.gis import GIS
import xml.dom.minidom as dom

def publish_service(portal_url=None, server_url=None, input_aprx=None, sddraft_folder=None):

    # get the PSA account information
    username, password = REDACTED 
    
    # Sign in to portal
    arcpy.SignInToPortal(portal_url, username, password)

    # Reference map to publish
    aprx = arcpy.mp.ArcGISProject(input_aprx)
    m = aprx.listMaps(wildcard="REDACTED")[0]

    # get the service name (equal to db name in our case)
    first_layer = m.listLayers()[0]
    dict = first_layer.connectionProperties
    service = dict['connection_info']['database']

    sddraft_filename = service + ".sddraft"
    sddraft_output_filename = os.path.join(sddraft_folder, sddraft_filename)

    # Create FeatureSharingDraft and set service properties
    sharing_draft = m.getWebLayerSharingDraft(server_type="FEDERATED_SERVER",
                                              service_type="MAP_IMAGE",
                                              service_name=service)

    sharing_draft.copyDataToServer = False
    sharing_draft.credits = "REDACTED"
    sharing_draft.description = ""
    sharing_draft.federatedServerUrl = server_url
    sharing_draft.portalFolder = "REDACTED"
    sharing_draft.serverFolder = "REDACTED"
    sharing_draft.summary = service.replace("_", " ") + " REDACTED"

    prj_name_list = service.replace("_", " ").split(" ")
    sharing_draft.tags = prj_name_list[0] + ", " + prj_name_list[1] + ", " + "REDACTED1, REDACTED2, REDACTED3"

    # Create Service Definition Draft file
    sharing_draft.exportToSDDraft(sddraft_output_filename)

    # Read the sddraft xml.
    print("Modifying xml file to enable feature access...")
    doc = dom.parse(sddraft_output_filename)

    # Find all elements named TypeName. This is where the server object extension
    # (SOE) names are defined.
    typeNames = doc.getElementsByTagName('TypeName')
    for typeName in typeNames:
        # Get the TypeName we want to enable.
        if typeName.firstChild.data == "FeatureServer":
            extension = typeName.parentNode
            for extElement in extension.childNodes:
                # Enable Feature Access.
                if extElement.tagName == 'Enabled':
                    extElement.firstChild.data = 'true'

    print("Modifying xml file to enable Z Defaults...")

    # Find all elements named Key.

    typeNames = doc.getElementsByTagName('Key')
    for typeName in typeNames:
        # Get the TypeName we want to enable.
        if typeName.firstChild.data == "enableZDefaults":
            parent = typeName.parentNode
            for extElement in parent.childNodes:
                if extElement.tagName == 'Value':
                    extElement.firstChild.data = 'true'

    # Output to a new sddraft.
    sddraft_mod_xml = service + '_mod_xml' + '.sddraft'
    sddraft_mod_xml_file = os.path.join(sddraft_folder, sddraft_mod_xml)
    f = open(sddraft_mod_xml_file, 'w')
    doc.writexml(f)
    f.close()

    # Stage Service
    sd_filename = service + ".sd"
    sd_output_filename = os.path.join(sddraft_folder, sd_filename)
    arcpy.server.StageService(in_service_definition_draft=sddraft_mod_xml_file,
                              out_service_definition=sd_output_filename)

    # Share to portal
    print("Uploading service definition...")
    arcpy.server.UploadServiceDefinition(in_sd_file=sd_output_filename,
                                         in_server=server_url)

    print("Successfully uploaded service.")

    # Sharing portal items
    ## Sign in to Portal with ArcGIS API for Python
    
    print(f"Sign in to Portal: {portal_url} ...")
    from arcgis.gis import GIS
    username, password = REDACTED
    gis = GIS(url=portal_url, username=username, password=password)

    item_name = service.split("/")[-1]

    items = gis.content.search(query=f"title:{item_name}",
                               max_items=2)
    for item in items:
        print(f"Sharing {item.title} {item.type}...")
        item.share(everyone=True)

    feature_service_url = f"{server_url}/rest/services/REDACTED/{service}/FeatureServer"

    print(f"Feature Service URL is: {feature_service_url}")
    return feature_service_url

View solution in original post

4 Replies
NathanHeickLACSD
Occasional Contributor III

My recommendation would be to use Fiddler or some other network traffic logger.  I did something similar for ArcMap and a hosted feature service in ArcGIS Online.  I suspect there is a REST call to create the item by ArcGIS Pro.  If not, look in the SD draft XML.

r3weber
New Contributor II

I would use the arcgis python api instead of arcpy for authentication and publishing.

https://developers.arcgis.com/python/api-reference/

 

AzinSharaf
Occasional Contributor II

I was able to finish the script. I am sharing it here in case you have same question.

import os
import arcpy
from arcgis.gis import GIS
import xml.dom.minidom as dom

def publish_service(portal_url=None, server_url=None, input_aprx=None, sddraft_folder=None):

    # get the PSA account information
    username, password = REDACTED 
    
    # Sign in to portal
    arcpy.SignInToPortal(portal_url, username, password)

    # Reference map to publish
    aprx = arcpy.mp.ArcGISProject(input_aprx)
    m = aprx.listMaps(wildcard="REDACTED")[0]

    # get the service name (equal to db name in our case)
    first_layer = m.listLayers()[0]
    dict = first_layer.connectionProperties
    service = dict['connection_info']['database']

    sddraft_filename = service + ".sddraft"
    sddraft_output_filename = os.path.join(sddraft_folder, sddraft_filename)

    # Create FeatureSharingDraft and set service properties
    sharing_draft = m.getWebLayerSharingDraft(server_type="FEDERATED_SERVER",
                                              service_type="MAP_IMAGE",
                                              service_name=service)

    sharing_draft.copyDataToServer = False
    sharing_draft.credits = "REDACTED"
    sharing_draft.description = ""
    sharing_draft.federatedServerUrl = server_url
    sharing_draft.portalFolder = "REDACTED"
    sharing_draft.serverFolder = "REDACTED"
    sharing_draft.summary = service.replace("_", " ") + " REDACTED"

    prj_name_list = service.replace("_", " ").split(" ")
    sharing_draft.tags = prj_name_list[0] + ", " + prj_name_list[1] + ", " + "REDACTED1, REDACTED2, REDACTED3"

    # Create Service Definition Draft file
    sharing_draft.exportToSDDraft(sddraft_output_filename)

    # Read the sddraft xml.
    print("Modifying xml file to enable feature access...")
    doc = dom.parse(sddraft_output_filename)

    # Find all elements named TypeName. This is where the server object extension
    # (SOE) names are defined.
    typeNames = doc.getElementsByTagName('TypeName')
    for typeName in typeNames:
        # Get the TypeName we want to enable.
        if typeName.firstChild.data == "FeatureServer":
            extension = typeName.parentNode
            for extElement in extension.childNodes:
                # Enable Feature Access.
                if extElement.tagName == 'Enabled':
                    extElement.firstChild.data = 'true'

    print("Modifying xml file to enable Z Defaults...")

    # Find all elements named Key.

    typeNames = doc.getElementsByTagName('Key')
    for typeName in typeNames:
        # Get the TypeName we want to enable.
        if typeName.firstChild.data == "enableZDefaults":
            parent = typeName.parentNode
            for extElement in parent.childNodes:
                if extElement.tagName == 'Value':
                    extElement.firstChild.data = 'true'

    # Output to a new sddraft.
    sddraft_mod_xml = service + '_mod_xml' + '.sddraft'
    sddraft_mod_xml_file = os.path.join(sddraft_folder, sddraft_mod_xml)
    f = open(sddraft_mod_xml_file, 'w')
    doc.writexml(f)
    f.close()

    # Stage Service
    sd_filename = service + ".sd"
    sd_output_filename = os.path.join(sddraft_folder, sd_filename)
    arcpy.server.StageService(in_service_definition_draft=sddraft_mod_xml_file,
                              out_service_definition=sd_output_filename)

    # Share to portal
    print("Uploading service definition...")
    arcpy.server.UploadServiceDefinition(in_sd_file=sd_output_filename,
                                         in_server=server_url)

    print("Successfully uploaded service.")

    # Sharing portal items
    ## Sign in to Portal with ArcGIS API for Python
    
    print(f"Sign in to Portal: {portal_url} ...")
    from arcgis.gis import GIS
    username, password = REDACTED
    gis = GIS(url=portal_url, username=username, password=password)

    item_name = service.split("/")[-1]

    items = gis.content.search(query=f"title:{item_name}",
                               max_items=2)
    for item in items:
        print(f"Sharing {item.title} {item.type}...")
        item.share(everyone=True)

    feature_service_url = f"{server_url}/rest/services/REDACTED/{service}/FeatureServer"

    print(f"Feature Service URL is: {feature_service_url}")
    return feature_service_url
NathanHeickLACSD
Occasional Contributor III

Thanks, Azin!  When I move my Python 2 code to Python 3, I will rewrite the code to use the latest OOTB functionality.  I see how so much of my custom code is now OOTB.