0

Trying to send a basic json array in a POST url API for the use of vmware vcenter.

I'm writing this in python which i'm new to.

Had a look at a few examples before posting this but they did'nt seem suited for this application.

I've Been googling similar examples and trying them, none of them have worked.

I have a large JSON array to post in this URL. Authentication is required to do so aswell hence a cookie session is requested first before executing the second API.

This API is used to clone a VM from a template in a library.

Just wondering if someone could help me. An understanding of vcenter is not required, just need help with a basic URL POST after session authentication and to be able to properly send a JSON array in the post.

The JSON array was developed using postman which appeared to have added a tonne of slashes, still no luck with or without them.

Could be just a simple typo that I can't see...

Thanks, heaps

I've tried altering the end header option in this line of the code where "data=json". Tried using params, data, JSON aswell.

item_detail_json_array=s.post('https://'+vcip+'/rest/vcenter/vm-template/library-items/37a0484b-bd8c-486f-b110-36c79c2295f7?action=deploy', data=json)

Also tried rearranging the JSON array with or without indents and newlines, with " and '.

import requests
import json
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

s=requests.Session()
s.verify=False

import json
vcip="xxx.xxx.xxx.xxx"





json = "{\r\n    \"spec\": {\r\n        \"description\": \"\",\r\n        \"disk_storage\": {\r\n            \"datastore\": \"datastore-25\",\r\n            \"storage_policy\": {\r\n                \"policy\": \"aa6d5a82-1c88-45da-85d3-3d74b91a5bad\",\r\n                \"type\": \"USE_SPECIFIED_POLICY\"\r\n            }\r\n        },\r\n        \"disk_storage_overrides\": [\r\n            {\r\n                \"key\": \"2000\",\r\n                \"value\": {\r\n                    \"datastore\": \"datastore-25\",\r\n                    \"storage_policy\": {\r\n                        \"policy\": \"aa6d5a82-1c88-45da-85d3-3d74b91a5bad\",\r\n                        \"type\": \"USE_SPECIFIED_POLICY\"\r\n                    }\r\n                }\r\n            }\r\n        ],\r\n        \"guest_customization\": {\r\n            \"name\": null\r\n        },\r\n        \"hardware_customization\": {\r\n            \"cpu_update\": {\r\n                \"num_cores_per_socket\": null,\r\n                \"num_cpus\": null\r\n            },\r\n            \"disks_to_update\": [\r\n                {\r\n                    \"key\": \"2000\",\r\n                    \"value\": {\r\n                        \"capacity\": 32212254721\r\n                    }\r\n                }\r\n            ],\r\n            \"memory_update\": {\r\n                \"memory\": null\r\n            },\r\n            \"nics\": [\r\n                {\r\n                    \"key\": \"4000\",\r\n                    \"value\": {\r\n                        \"network\": \"network-26\"\r\n                    }\r\n                }\r\n            ]\r\n        },\r\n        \"name\": \"cloned via api6\",\r\n        \"placement\": {\r\n            \"folder\": \"group-v18\",\r\n            \"resource_pool\": \"resgroup-23\"\r\n        },\r\n        \"powered_on\": true,\r\n        \"vm_home_storage\": {\r\n            \"datastore\": \"datastore-25\",\r\n            \"storage_policy\": {\r\n                \"policy\": \"aa6d5a82-1c88-45da-85d3-3d74b91a5bad\",\r\n                \"type\": \"USE_SPECIFIED_POLICY\"\r\n            }\r\n        }\r\n    }\r\n}"

def get_vc_session(vcip,username,password):
         s.post('https://'+vcip+'/rest/com/vmware/cis/session', auth=(username,password))
         return s


def get_vms(vcip):
        item_detail_json_array=s.post('https://'+vcip+'/rest/vcenter/vm-template/library-items/37a0484b-bd8c-486f-b110-36c79c2295f7?action=deploy', data=json)
        return item_detail_json_array


vcsession = get_vc_session(vcip,"administrator@vcenterserver","password1234")

itemid_json_array = get_vms(vcip)   #executes the api enquiry stores as array


for x in itemid_json_array:

    print(x) # just to get the response working for now

UPDATE--------------------------------

This code is working instead, seems perhaps vcenter only wants the session ID posted in the header in this method. Ugly and not very simple but it works to say the least. I tried just performing the one URL request, having all the parameters in there and using the AUTH parameter aswell, but vcenter kept spitting the dummy. So I believe i've narrowed it down to an authentication error. Seems to work okay with my original solution, however in this case, we're posting a large json array. In this case, Vcenter does not seem to like what is being spat out by the previous solution after the session request attempt is done, and seems to prefer the session id presented in the header when requesting the second API to clone the VM in vcenter. Most of this idea came form the example that POSTMAN spat out using an SDK library from vcenter.

import requests
import json


s=requests.Session()
s.verify=False


vcip = "xxx.xxx.xxx.xxx"
vmname = "testclonepython2"
username = 'administrator@vcenterdomain'
password = 'vcenterpass'

def get_vc_session(username,password):
         s.post('https://'+vcip+'/rest/com/vmware/cis/session', auth=(username,password))
         return s


get_vc_session(username,password)


cookie = s.cookies['vmware-api-session-id']


url = "https://"+vcip+"/rest/vcenter/vm-template/library-items/37a0484b-bd8c-486f-b110-36c79c2295f7"

querystring = {"action":"deploy"}

payload = "{\n    \"spec\": {\n        \"description\": \"\",\n        \"disk_storage\": {\n            \"datastore\": \"datastore-25\",\n            \"storage_policy\": {\n                \"policy\": \"aa6d5a82-1c88-45da-85d3-3d74b91a5bad\",\n                \"type\": \"USE_SPECIFIED_POLICY\"\n            }\n        },\n        \"disk_storage_overrides\": [\n            {\n                \"key\": \"2000\",\n                \"value\": {\n                    \"datastore\": \"datastore-25\",\n                    \"storage_policy\": {\n                        \"policy\": \"aa6d5a82-1c88-45da-85d3-3d74b91a5bad\",\n                        \"type\": \"USE_SPECIFIED_POLICY\"\n                    }\n                }\n            }\n        ],\n        \"guest_customization\": {\n            \"name\": null\n        },\n        \"hardware_customization\": {\n            \"cpu_update\": {\n                \"num_cores_per_socket\": null,\n                \"num_cpus\": null\n            },\n            \"disks_to_update\": [\n                {\n                    \"key\": \"2000\",\n                    \"value\": {\n                        \"capacity\": 32212254721\n                    }\n                }\n            ],\n            \"memory_update\": {\n                \"memory\": null\n            },\n            \"nics\": [\n                {\n                    \"key\": \"4000\",\n                    \"value\": {\n                        \"network\": \"network-26\"\n                    }\n                }\n            ]\n        },\n        \"name\": \""+vmname+"\",\n        \"placement\": {\n            \"folder\": \"group-v18\",\n            \"resource_pool\": \"resgroup-23\"\n        },\n        \"powered_on\": true,\n        \"vm_home_storage\": {\n            \"datastore\": \"datastore-25\",\n            \"storage_policy\": {\n                \"policy\": \"aa6d5a82-1c88-45da-85d3-3d74b91a5bad\",\n                \"type\": \"USE_SPECIFIED_POLICY\"\n            }\n        }\n    }\n}"
headers = {
    'Content-Type': "application/json",
    'Accept': "*/*",
    'Cache-Control': "no-cache",
    'Host': vcip,
    'vmware-api-session-id': cookie,
    'Accept-Encoding': "gzip, deflate",
    'Connection': "keep-alive",
    'cache-control': "no-cache"
    }


response = requests.request("POST", url, data=payload, headers=headers, params=querystring, verify=False)

print(response.text)
ohgetout
  • 3
  • 3
  • You should probably try and format the question better as a lot of that looks like it should be as code but is not. This will make it easier for people to help you (I know certainly for me I find looking at code easier in a code font and colouring) – Nat Cecil Sep 30 '19 at 17:31
  • It is formatted isn’t it? – ohgetout Oct 01 '19 at 02:34

1 Answers1

0

Don't try to manually build the JSON string whilst backslashing quotes, etc.

Use the functionality to pass a python dictionary which is built into requests. These arguments are:

params: for URL parameters

data: for POST payload data

Also check the actual documentation on the API to see what your requests should look like: https://vmware.github.io/vsphere-automation-sdk-rest/6.7.1/index.html

So the template library deploy function expects a POST request like:

POST https://{server}/rest/vcenter/vm-template/library-items/{template_library_item}?action=deploy

They give a sample request body payload, which is almost a valid python datastructure, except for near the end:

"powered_on": true,

should be changed to:

"powered_on": True,

You should really be building this dynamically depending on what you want these variables to be, but lets go with the example, as a valid python data structure:

req_body = {'spec': {'description': 'string', 'disk_storage': {'datastore': 'obj-103', 'storage_policy': {'policy': 'obj-103', 'type': 'USE_SPECIFIED_POLICY'}}, 'disk_storage_overrides': [{'key': 'obj-103', 'value': {'datastore': 'obj-103', 'storage_policy': {'policy': 'obj-103', 'type': 'USE_SPECIFIED_POLICY'}}}], 'guest_customization': {'name': 'string'}, 'hardware_customization': {'cpu_update': {'num_cores_per_socket': 1, 'num_cpus': 1}, 'disks_to_remove': ['obj-103', 'obj-103'], 'disks_to_update': [{'key': 'obj-103', 'value': {'capacity': 1}}], 'memory_update': {'memory': 1}, 'nics': [{'key': 'obj-103', 'value': {'network': 'obj-103'}}]}, 'name': 'string', 'placement': {'cluster': 'obj-103', 'folder': 'obj-103', 'host': 'obj-103', 'resource_pool': 'obj-103'}, 'powered_on': True, 'vm_home_storage': {'datastore': 'obj-103', 'storage_policy': {'policy': 'obj-103', 'type': 'USE_SPECIFIED_POLICY'}}}}

Notice this also has ?action=deploy on the URL, so we can do a similar thing like this:

req_params = {'action':'deploy'}

Now build the request like:

server = 'localhost' # My example
item = '37a0484b-bd8c-486f-b110-36c79c2295f7'
url = 'https://%s/rest/vcenter/vm-template/library-items/%s' % (server,item)

resp = r.post(url, params = req_params, data = req_body)

If you were in the console at this point you could see the full URL:

>>> resp.url
'https://localhost/rest/vcenter/vm-template
/library-items/37a0484b-bd8c-486f-b110-36c79c2295f7?action=deploy'

And the JSON response:

>>> resp.json()

which should give something like:

{
    "value": "obj-103"
}

Where value is the "Identifier of the deployed virtual machine" as per the API documentation.


EDIT regarding auth

I don't have this software to test, only ESXi which doesn't have the REST API. From this section I think you need to:

  • Connect to lookup service
  • Discover the secure token service (STS) endpoint URL
  • Connect to the secure token service to obtain a SAML token.

But the create section, only mentions the response which is a secret string (presumably you then provide this to other REST endpoints), but not how to provide the SAML token in the first place, unless I'm missing something.

Possibly see this answer: https://stackoverflow.com/a/56185704/2052575

v25
  • 7,096
  • 2
  • 20
  • 36
  • Thankyou for taking the time to provide the response you have provided. Although, I tried to implement your recommendations, I'm still getting the same response. I'd post what I had done but not sure how to on this particular forum. I've also noticed that if I intentionally enter the wrong username and password, the response does not change?? After some troubleshooting the problem seems to be the way the json is being posted I think.... – ohgetout Oct 01 '19 at 16:35
  • Actually, I've just commented out the section that requests the session, and the same error is occurring, I think it may be some authentication bug in my script. I'll keep looking. – ohgetout Oct 01 '19 at 16:42
  • i've also noticed this variable isn't being used. vcsession = get_vc_session(vcip,"administrator@vcenterserver","password1234") – ohgetout Oct 01 '19 at 16:47
  • You can edit your question to add further details, although you could ask another question about the auth. See my update regarding auth. Feel free to link back to /include this update if you raise another question, this one's becoming a bit cluttered. Although maybe this will help: https://stackoverflow.com/a/56185704/2052575 – v25 Oct 01 '19 at 17:28
  • No probs. You should mark the answer as correct if it solved the issue. – v25 Oct 01 '19 at 23:17