aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFilipp Lepalaan <filipp@mac.com>2015-07-31 09:11:06 +0300
committerFilipp Lepalaan <filipp@mac.com>2015-07-31 09:11:06 +0300
commit38fc774af945ddeb08f609b8a72594a80699b2b2 (patch)
tree162d55011924612e973be1ae0f8fdba1cfa6218b
parent5c6b195718765b2e5c9eaee183a59b44fd09533b (diff)
downloadpy-gsxws-38fc774af945ddeb08f609b8a72594a80699b2b2.tar.gz
py-gsxws-38fc774af945ddeb08f609b8a72594a80699b2b2.tar.bz2
py-gsxws-38fc774af945ddeb08f609b8a72594a80699b2b2.zip
Added SSH cert support
-rw-r--r--README.rst22
-rw-r--r--gsxws/core.py74
-rw-r--r--requirements.pip1
-rw-r--r--setup.py3
4 files changed, 56 insertions, 44 deletions
diff --git a/README.rst b/README.rst
index d45c8d5..65beb57 100644
--- a/README.rst
+++ b/README.rst
@@ -13,9 +13,8 @@ Requirements
************
- Python 2.7 or later
-- lxml
-- PyYAML
-- A valid Apple ID with access to GSX Web Services.
+- contents of requirements.pip
+- GSX client certs and valid Apple ID with access to GSX Web Services
Installation::
@@ -33,13 +32,26 @@ Usage
It goes a little something like this::
# check warranty status
+ import os
import gsxws
- gsxws.connect(apple_id, password, sold_to)
+ os.environ['GSX_CERT'] = '/path/to/gsx/client/cert.pem'
+ os.environ['GSX_KEY'] = '/path/to/gsx/client/cert_private_key.pem'
+ gsxws.connect(apple_id, sold_to)
mac = gsxws.Product('70033CDFA4S')
mac.warranty()
# get available parts for this machine
mac.parts()
-
Check the tests-folder for more examples.
+
+
+***
+FAQ
+***
+
+Q: My script keeps prompting me for the private key passphrase - how could I automate this?
+A: One way would be to remove the passphrase from the key:
+
+ $ openssl rsa -in privatekey.pem -out privatekey.nopass.pem
+
diff --git a/gsxws/core.py b/gsxws/core.py
index b19cfeb..d5b6d5e 100644
--- a/gsxws/core.py
+++ b/gsxws/core.py
@@ -24,6 +24,7 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""
+import os
import re
import json
import base64
@@ -31,7 +32,7 @@ import shelve
import os.path
import hashlib
import logging
-import httplib
+import requests
import tempfile
import objectify
from urlparse import urlparse
@@ -39,9 +40,9 @@ import xml.etree.ElementTree as ET
from datetime import date, time, datetime, timedelta
-VERSION = "0.91"
+VERSION = "0.92"
-GSX_ENV = "it" # it, ut or pr
+GSX_ENV = "ut" # it, ut or pr
GSX_LANG = "en"
GSX_REGION = "emea"
GSX_LOCALE = "en_XXX"
@@ -58,6 +59,8 @@ GSX_REGIONS = (
('007', "Latin America"),
)
+GSX_TIMEZONE = 'CEST'
+
GSX_TIMEZONES = (
('PST', "UTC - 8h (Pacific Standard Time)"),
('PDT', "UTC - 7h (Pacific Daylight Time)"),
@@ -95,8 +98,8 @@ ENVIRONMENTS = (
('it', "Testing"),
)
-GSX_HOSTS = {'pr': 'ws2', 'it': 'wsit', 'ut': 'wsut'}
-GSX_URL = "https://gsx{env}.apple.com/gsx-ws/services/{region}/asp"
+GSX_HOSTS = {'pr': '', 'it': 'it', 'ut': 'ut'}
+GSX_URL = "https://gsxapi{env}.apple.com/gsx-ws/services/{region}/asp"
def validate(value, what=None):
@@ -120,7 +123,7 @@ def validate(value, what=None):
result = None
if not isinstance(value, basestring):
- raise ValueError('%s is not valid input' % value)
+ raise ValueError('%s is not valid input (%s != string)' % (value, type(value)))
rex = {
'partNumber': r'^([A-Z]{1,2})?\d{3}\-?(\d{4,5}|[A-Z]{1,2})(/[A-Z])?$',
@@ -269,32 +272,29 @@ class GsxRequest(object):
global GSX_ENV, GSX_REGION, GSX_HOSTS, GSX_URL, GSX_TIMEOUT
self._url = GSX_URL.format(env=GSX_HOSTS[GSX_ENV], region=GSX_REGION)
- parsed = urlparse(self._url)
logging.debug(self._url)
logging.debug(xmldata)
+ headers = {
+ 'User-Agent' : "py-gsxws %s" % VERSION,
+ 'Content-type' : 'text/xml; charset="UTF-8"',
+ 'SOAPAction' : '"%s"' % method
+ }
+
+ # Send GSX client certs with every request
try:
- # Python 2.6.9 and newer
- # @TODO: Implement proper verified context
- from ssl import _create_unverified_context
- ws = httplib.HTTPSConnection(parsed.netloc,
- timeout=GSX_TIMEOUT,
- context=_create_unverified_context())
- except ImportError:
- ws = httplib.HTTPSConnection(parsed.netloc, timeout=GSX_TIMEOUT)
-
- ws.putrequest("POST", parsed.path)
- ws.putheader("User-Agent", "py-gsxws %s" % VERSION)
- ws.putheader("Content-type", 'text/xml; charset="UTF-8"')
- ws.putheader("Content-length", "%d" % len(xmldata))
- ws.putheader("SOAPAction", '"%s"' % method)
- ws.endheaders()
- ws.send(xmldata)
+ self.gsx_cert = os.environ['GSX_CERT']
+ self.gsx_key = os.environ['GSX_KEY']
+ except KeyError as e:
+ raise GsxError('SSL configuration error: %s' % e)
try:
- return ws.getresponse()
- except Exception, e:
+ return requests.post(self._url, cert=(self.gsx_cert, self.gsx_key),
+ data=xmldata,
+ headers=headers,
+ timeout=GSX_TIMEOUT)
+ except Exception as e:
raise GsxError('GSX connection failed: %s' % e)
def _submit(self, method, response=None, raw=False):
@@ -318,13 +318,13 @@ class GsxRequest(object):
data = ET.tostring(self.env, "UTF-8")
res = self._send(method, data)
- xml = res.read()
+ xml = res.text.encode('utf-8')
self.xml_response = xml
- if res.status > 200:
+ if res.status_code > 200:
raise GsxError(xml=xml, url=self._url)
- logging.debug("Response: %s %s %s" % (res.status, res.reason, xml))
+ logging.debug("Response: %s %s %s" % (res.status_code, res.reason, xml))
if raw:
return ET.fromstring(self.xml_response)
@@ -438,11 +438,10 @@ class GsxSession(GsxObject):
_cache = None
_namespace = "glob:"
- def __init__(self, user_id, password, sold_to, language, timezone):
+ def __init__(self, user_id, sold_to, language, timezone):
global GSX_ENV
self.userId = user_id
- self.password = password
self.languageCode = language
self.userTimeZone = timezone
self.serviceAccountNo = str(sold_to)
@@ -480,7 +479,7 @@ class GsxSession(GsxObject):
return GsxRequest(LogoutRequest=self)
-def connect(user_id, password, sold_to,
+def connect(user_id, sold_to,
environment=GSX_ENV,
language=GSX_LANG,
timezone="CEST",
@@ -495,12 +494,12 @@ def connect(user_id, password, sold_to,
global GSX_LOCALE
global GSX_REGION
+ GSX_ENV = environment
GSX_LANG = language
GSX_REGION = region
GSX_LOCALE = locale
- GSX_ENV = environment
- act = GsxSession(user_id, password, sold_to, language, timezone)
+ act = GsxSession(user_id, sold_to, language, timezone)
return act.login()
@@ -511,12 +510,11 @@ if __name__ == '__main__':
parser = argparse.ArgumentParser(description="Communicate with GSX Web Services")
parser.add_argument("user_id")
- parser.add_argument("password")
parser.add_argument("sold_to")
- parser.add_argument("--language", default="en")
- parser.add_argument("--timezone", default="CEST")
- parser.add_argument("--environment", default="it")
- parser.add_argument("--region", default="emea")
+ parser.add_argument("--language", default=GSX_LANG)
+ parser.add_argument("--timezone", default=GSX_TIMEZONE)
+ parser.add_argument("--environment", default=GSX_ENV)
+ parser.add_argument("--region", default=GSX_REGION)
args = parser.parse_args()
logging.basicConfig(level=logging.DEBUG)
diff --git a/requirements.pip b/requirements.pip
index 6c0a1cb..d33bb35 100644
--- a/requirements.pip
+++ b/requirements.pip
@@ -1,2 +1,3 @@
lxml
yaml
+requests
diff --git a/setup.py b/setup.py
index 07c3b7f..57861cc 100644
--- a/setup.py
+++ b/setup.py
@@ -1,8 +1,9 @@
from setuptools import setup, find_packages
+from gsxws.core import VERSION
setup(
name="gsxws",
- version="0.56",
+ version=VERSION,
description="Library for communicating with GSX Web Services API.",
long_description=open('README.rst').read(),
install_requires=['PyYAML', 'lxml'],