I’m using Ansible to purchase a domain name using the namecheap.com api. Here is a example of the playbook.
-
name: Purchase Domain Name
local_action: >
uri url=https://api.sandbox.namecheap.com/xml.response
method=GET body=“{{ namecheap_purchase_domain_name }}”
status_code=200 HEADER_Content-Type=“application/x-www-form-urlencoded”
register: domain_name_purchase
-
debug: msg=“{{ domain_name_purchase }}”
The output looks like this:
ok: [162.243.95.241] => {“cache_control”: “private”, “changed”: false, “content”: “<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<ApiResponse Status="OK" xmlns="http://api.namecheap.com/xml.response\”>\r\n \r\n \r\n namecheap.domains.getList\r\n <CommandResponse Type="namecheap.domains.getList">\r\n \r\n <Domain ID="33320" Name="asdfasdfasdfasdfasdfasdfasdfjk123.com" User="username" Created="11/19/2013" Expires="11/19/2014" IsExpired="false" IsLocked="false" AutoRenew="false" WhoisGuard="NOTPRESENT" />\r\n <Domain ID="33321" Name="avd.com" User="username" Created="11/19/2013" Expires="11/19/2014" IsExpired="false" IsLocked="false" AutoRenew="false" WhoisGuard="NOTPRESENT" />\r\n <Domain ID="33319" Name="domain.com" User="username" Created="11/19/2013" Expires="11/19/2014" IsExpired="false" IsLocked="false" AutoRenew="false" WhoisGuard="NOTPRESENT" />\r\n <Domain ID="33318" Name="domain.com" User="username" Created="11/19/2013" Expires="11/19/2014" IsExpired="false" IsLocked="false" AutoRenew="false" WhoisGuard="NOTPRESENT" />\r\n <Domain ID="33322" Name="domain11.com" User="username" Created="11/19/2013" Expires="11/19/2014" IsExpired="false" IsLocked="false" AutoRenew="false" WhoisGuard="NOTPRESENT" />\r\n <Domain ID="33323" Name="domain 13.com" User="username" Created="11/19/2013" Expires="11/19/2014" IsExpired="false" IsLocked="false" AutoRenew="false" WhoisGuard="NOTPRESENT" />\r\n <Domain ID="32804" Name="domain.com" User="username" Created="11/01/2013" Expires="11/02/2014" IsExpired="false" IsLocked="false" AutoRenew="false" WhoisGuard="NOTPRESENT" />\r\n <Domain ID="32805" Name="domain3.com" User="username" Created="11/01/2013" Expires="11/02/2014" IsExpired="false" IsLocked="false" AutoRenew="false" WhoisGuard="NOTPRESENT" />\r\n <Domain ID="32806" Name="domain 4.com" User="username" Created="11/01/2013" Expires="11/02/2014" IsExpired="false" IsLocked="false" AutoRenew="false" WhoisGuard="NOTPRESENT" />\r\n <Domain ID="33316" Name="domain5.com" User="username" Created="11/19/2013" Expires="11/19/2014" IsExpired="false" IsLocked="false" AutoRenew="false" WhoisGuard="NOTPRESENT" />\r\n \r\n \r\n 10\r\n 1\r\n 20\r\n \r\n \r\n WEB1-SANDBOX1\r\n –5:00\r\n 0.096\r\n", “content_length”: “2478”, “content_location”: “https://api.sandbox.namecheap.com/xml.response”, “content_type”: “text/xml; charset=utf-8”, “date”: “Wed, 20 Nov 2013 02:06:37 GMT”, “item”: “”, “redirected”: false, “server”: “Microsoft-IIS/7.0”, “status”: 200, “x_aspnet_version”: “4.0.30319”, “x_powered_by”: “ASP.NET”}
I’m interested in the XML inside the ‘content’ container. Is there any way to query this output so I know if the purchase was successful or not
something like
when: ‘“FOO” in domain_name_purchase.stdout’
where FOO is a string indicating successful purchase.
Hope this helps,
K
Thanks Kahlil,
Thats a great idea. Thank you. I’ve updated my code now:
-
name: Purchase Domain Name
local_action: >
uri
url=https://api.sandbox.namecheap.com/xml.response
method=GET
body=“{{ namecheap_purchase_domain_name }}”
status_code=200
HEADER_Content-Type=“application/x-www-form-urlencoded”
return_content=yes
register: domain_name_purchase
-
command: /bin/echo SUCCESS
when: ‘“ApiResponse Status=OK” in domain_name_purchase.stdout’
Now I’m getting this error:
TypeError: argument of type ‘StrictUndefined’ is not iterable
yes, you can’t call things on undefined variables.
Perhaps there’s a copy paste error and that variable isn’t named what you expect.
Also, it should NOT be a thing, but might be in some versions of ansible, make sure there’s not a trailing space after the register line. If there is, let me know, I’m just being paranoid that that could be a thing.
Hmm … just searched by ansible setup because I’ve seen this recently. Here’s an example where selinux.stdout is undefined when it perhaps should be an empty string.
this is mainly to fix an iptables rpm bug
- name: ensure selinux contexts under /sbin are correct
command: /sbin/restorecon -rv /sbin/
register: selinux
changed_when: >
selinux.stdout is defined and ‘reset’ in selinux.stdout
I would agree if stdout is blank it should be returned as an empty string.
If you can reproduce this on 1.3.X/1.4 please file a ticket and we’ll repro on our end and make sure 1.4 or 1.5 gets a fix for it.
rizo:ansible ansible --version
ansible 1.4 (devel b7971a426c) last updated 2013/11/18 08:39:30 (GMT +1100)
Will file a ticket.
Woo Hoo! Always good to help discover a bug. I’m still struggling with parsing the output. my variable {{ domain_name_purchase }} is returned what I called in the url while “return_content=yes” is returned the error code I want to parse. How do I manipulate the returned content?
Hi David,
I’m having trouble reproducing this issue. Have been taking a lot of pain killers over the last week, so this may just be because my brain is mush. What version of ansible are using?
K
You might want to have a look at
http://jinja.pocoo.org/docs/templates/#builtin-filters
for some jinja type things that you can do
Also there are some ansible docs on filters somewhere on the website.
The variable is python-ish so I believe some python constructs might work.
K
Kahlil (Kal) Hodgson GPG: C9A02289
Head of Technology (m) +61 (0) 4 2573 0382
DealMax Pty Ltd (w) +61 (0) 3 9008 5281
Suite 1415
401 Docklands Drive
Docklands VIC 3008 Australia
"All parts should go together without forcing. You must remember that
the parts you are reassembling were disassembled by you. Therefore,
if you can't get them together again, there must be a reason. By all
means, do not use a hammer." -- IBM maintenance manual, 1925
For purposes of Google history, let us know what you want to do, and we can suggest something.
I’m running version 1.4 and I’m looking to detect what error returns
<ApiResponse Status="ERROR"
and what that error is:
<Error Number="3028166">540:Object exists
or a success
ApiResponse Status="OK"
Thanks for the help guys.
Cheers,
David
Maybe someone can help me understand my python better. domain_name_purchase is dict object that as far as I can tell has no attributes or elements. I can echo it but beyond that I’m stuck.
try
- debug: var=domain_name_purchase
should show you all the elements of the dict
K
Kahlil, Thank you! That got me one step closer. I’m using:
- debug: var=domain_name_purchase.content
To return the data I need. How do I drill down even further?
I’d like to return “ApiResponse Status” and check if it was ERROR or SUCCESS and what “Error Number” is was
ok: [162.243.95.241] => {
“domain_name_purchase.content”: “<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<ApiResponse Status="ERROR" xmlns="[http://api.namecheap.com/xml.response\](http://api.namecheap.com/xml.response\)”>\r\n \r\n <Error Number="4014104">Possible duplicate create command for unavailable domain. Try again after 11/20/2013 7:29:46 AM UTC\r\n \r\n \r\n namecheap.domains.create\r\n <CommandResponse Type="namecheap.domains.create">\r\n <DomainCreateResult Domain="elitereceipt202321412341234.com" ChargedAmount="0" DomainID="0" OrderID="0" TransactionID="0" WhoisguardEnable="false" FreePositiveSSL="false" NonRealTimeDomain="false" />\r\n \r\n WEB1-SANDBOX1\r\n –5:00\r\n 0.02\r\n",
“item”: “”
}
You’ve drilled down as far as you can go in the data structure. What you have got is a string. You will need to do some kind of string munging to get any further. I think you might be able to use the python ‘find’ method on the string, e.g., {{ domain_name_purchase.content.find(“Error”) }}, but I’m not sure that’s what you want. Someone on this list who actually knows python might be able to help here and I’d be keen to see how the experts approach it. It would be great if there was a filter (say ‘xml2dict’) that would magically turn an xml string into python/jinja2 data structure.
K
when: “‘foo’ in variable”
when: “‘foo’ not in variable”
is usually cleaner than find.
find in Python returns -1 if a string is not found, so what Kahlil suggested above needs to add that the comparison to -1.
I think what David is looking for, and what I was alluding to, was something like a regexp capture. I know how I’d do this in Perl, but have no idea what the magic Python invocation would be. That is, something like: {{ foo_string.capture(‘Error=“(\d+)”’, 1) }} to give me back the error number, perhaps for later use in a template. Is there such a thing in Python?
K
Kahlil is correct. Thats exactly what I’m looking for. Thank for the help guys.