pax_global_header00006660000000000000000000000064134434563420014522gustar00rootroot0000000000000052 comment=c6e095cad1ab67f8b48f3deb9a350dfa7283b9a2 transip-api-2.0.0/000077500000000000000000000000001344345634200137505ustar00rootroot00000000000000transip-api-2.0.0/.gitignore000066400000000000000000000004171344345634200157420ustar00rootroot00000000000000# Python /build /bin /dist /include /lib /local /*.egg-info /*.egg *.pyc *.pyo # Test artifact /.coverage # Don't check in unencrypted key /decrypted_key /encrypted_key # PHP Examples /transipAPI # Generated documentation /.*html docs/_build # Editors /.idea /*.iml transip-api-2.0.0/.pylintrc000066400000000000000000000207241344345634200156220ustar00rootroot00000000000000[MASTER] # Specify a configuration file. #rcfile= # Python code to execute, usually for sys.path manipulation such as # pygtk.require(). #init-hook= # Profiled execution. profile=no # Add files or directories to the blacklist. They should be base names, not # paths. ignore=CVS # Pickle collected data for later comparisons. persistent=yes # List of plugins (as comma separated values of python modules names) to load, # usually to register additional checkers. load-plugins= [MESSAGES CONTROL] # Enable the message, report, category or checker with the given id(s). You can # either give multiple identifier separated by comma (,) or put this option # multiple time. See also the "--disable" option for examples. #enable= # Disable the message, report, category or checker with the given id(s). You # can either give multiple identifiers separated by comma (,) or put this # option multiple times (only on the command line, not in the configuration # file where it should appear only once).You can also use "--disable=all" to # disable everything first and then reenable specific checks. For example, if # you want to run only the similarities checker, you can use "--disable=all # --enable=similarities". If you want to run only the classes checker, but have # no Warning level messages displayed, use"--disable=all --enable=classes # --disable=W" #disable= [REPORTS] # Set the output format. Available formats are text, parseable, colorized, msvs # (visual studio) and html. You can also give a reporter class, eg # mypackage.mymodule.MyReporterClass. output-format=colorized # Put messages in a separate file for each module / package specified on the # command line instead of printing them on stdout. Reports (if any) will be # written in a file name "pylint_global.[txt|html]". files-output=no # Tells whether to display a full report or only the messages reports=no # Python expression which should return a note less than 10 (10 is the highest # note). You have access to the variables errors warning, statement which # respectively contain the number of errors / warnings messages and the total # number of statements analyzed. This is used by the global evaluation report # (RP0004). evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) # Add a comment according to your evaluation note. This is used by the global # evaluation report (RP0004). comment=no # Template used to display messages. This is a python new-style format string # used to format the message information. See doc for all details #msg-template= [VARIABLES] # Tells whether we should check for unused import in __init__ files. init-import=no # A regular expression matching the beginning of the name of dummy variables # (i.e. not used). dummy-variables-rgx=_$|dummy # List of additional names supposed to be defined in builtins. Remember that # you should avoid to define new builtins when possible. additional-builtins= [TYPECHECK] # Tells whether missing members accessed in mixin class should be ignored. A # mixin class is detected if its name ends with "mixin" (case insensitive). ignore-mixin-members=yes # List of classes names for which member attributes should not be checked # (useful for classes with attributes dynamically set). ignored-classes=SQLObject # When zope mode is activated, add a predefined set of Zope acquired attributes # to generated-members. zope=no # List of members which are set dynamically and missed by pylint inference # system, and so shouldn't trigger E0201 when accessed. Python regular # expressions are accepted. generated-members=REQUEST,acl_users,aq_parent [FORMAT] # Maximum number of characters on a single line. max-line-length=120 # Regexp for a line that is allowed to be longer than the limit. ignore-long-lines=^\s*(# )??$ # Allow the body of an if to be on the same line as the test if there is no # else. single-line-if-stmt=yes # List of optional constructs for which whitespace checking is disabled no-space-check=trailing-comma,dict-separator # Maximum number of lines in a module max-module-lines=1000 # String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 # tab). indent-string=' ' [BASIC] # Required attributes for module, separated by a comma required-attributes= # List of builtins function names that should not be used, separated by a comma bad-functions=map,filter,apply,input # Regular expression which should only match correct module names module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ # Regular expression which should only match correct module level names const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ # Regular expression which should only match correct class names class-rgx=[A-Z_][a-zA-Z0-9]+$ # Regular expression which should only match correct function names function-rgx=[a-z_][a-z0-9_]{2,30}$ # Regular expression which should only match correct method names method-rgx=[a-z_][a-z0-9_]{2,30}$ # Regular expression which should only match correct instance attribute names attr-rgx=[a-z_][a-z0-9_]{2,30}$ # Regular expression which should only match correct argument names argument-rgx=[a-z_][a-z0-9_]{2,30}$ # Regular expression which should only match correct variable names variable-rgx=[a-z_][a-z0-9_]{2,30}$ # Regular expression which should only match correct attribute names in class # bodies class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ # Regular expression which should only match correct list comprehension / # generator expression variable names inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ # Good variable names which should always be accepted, separated by a comma good-names=i,j,k,ex,Run,_ # Bad variable names which should always be refused, separated by a comma bad-names=foo,bar,baz,toto,tutu,tata # Regular expression which should only match function or class names that do # not require a docstring. no-docstring-rgx=__.*__ # Minimum line length for functions/classes that require docstrings, shorter # ones are exempt. docstring-min-length=-1 [SIMILARITIES] # Minimum lines number of a similarity. min-similarity-lines=4 # Ignore comments when computing similarities. ignore-comments=yes # Ignore docstrings when computing similarities. ignore-docstrings=yes # Ignore imports when computing similarities. ignore-imports=no [MISCELLANEOUS] # List of note tags to take in consideration, separated by a comma. notes=FIXME,XXX,TODO [CLASSES] # List of interface methods to ignore, separated by a comma. This is used for # instance to not check methods defines in Zope's Interface base class. ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by # List of method names used to declare (i.e. assign) instance attributes. defining-attr-methods=__init__,__new__,setUp # List of valid names for the first argument in a class method. valid-classmethod-first-arg=cls # List of valid names for the first argument in a metaclass class method. valid-metaclass-classmethod-first-arg=mcs [DESIGN] # Maximum number of arguments for function / method max-args=6 # Argument names that match this expression will be ignored. Default to name # with leading underscore ignored-argument-names=_.* # Maximum number of locals for function / method body max-locals=15 # Maximum number of return / yield for function / method body max-returns=6 # Maximum number of branch for function / method body max-branches=12 # Maximum number of statements in function / method body max-statements=50 # Maximum number of parents for a class (see R0901). max-parents=7 # Maximum number of attributes for a class (see R0902). max-attributes=7 # Minimum number of public methods for a class (see R0903). min-public-methods=2 # Maximum number of public methods for a class (see R0904). max-public-methods=20 [IMPORTS] # Deprecated modules which should not be used, separated by a comma deprecated-modules=regsub,TERMIOS,Bastion,rexec # Create a graph of every (i.e. internal and external) dependencies in the # given file (report RP0402 must not be disabled) import-graph= # Create a graph of external dependencies in the given file (report RP0402 must # not be disabled) ext-import-graph= # Create a graph of internal dependencies in the given file (report RP0402 must # not be disabled) int-import-graph= [EXCEPTIONS] # Exceptions that will emit a warning when being caught. Defaults to # "Exception" overgeneral-exceptions=Exception transip-api-2.0.0/.travis.yml000066400000000000000000000012671344345634200160670ustar00rootroot00000000000000sudo: no language: python cache: pip python: - "3.6" - "3.5" - "3.4" - "2.7" install: - pip install -r dev_requirements.txt script: - nosetests --rednose --with-coverage --cover-package=transip - pylint --rcfile=.pylintrc transip # Deploy a new release to PyPi for every new tag on the 'master' branch on the # repository 'benkonrath/transip-api'. deploy: provider: pypi user: roaldnefs password: secure: "ahpUlrwDpSzVETim897QkLZNGdK3MUZJWghAd3U9idPaIo/Ax21jgPJ0emRQxBOEmK+ztcxVkm5GKU5IZQYbBbTZeppi+xV0a3MeCwmMIrwDZCYxc8uZPjbqmqLjaO3dd5lNcpOXkDXXhr5LGtUIsRKhI9oLb6l+ZfbmuF4niBw=" on: repo: benkonrath/transip-api tags: true branch: master python: 3.6 transip-api-2.0.0/CHANGELOG.rst000066400000000000000000000027141344345634200157750ustar00rootroot00000000000000========= Changelog ========= This document records all notable changes to `transip-api `_. This project adheres to `Semantic Versioning `_. `2.0.0`_ (2019-03-17) --------------------- * Changed default cryptography library from rsa to cryptography `1.0.1`_ (2019-03-17) --------------------- * Fixed bytes input for cryptography library `1.0.0`_ (2019-03-15) --------------------- * Added cryptography as an optional replacement for rsa library (cryptography doesn't require the private key to be converted) * Fixed ordering Vps * Added option to clone Vps * Added availability zones for Vps * Added option to specify private key directly `0.4.1`_ (2018-08-03) --------------------- * Many improvements and bug fixes `0.4.0`_ (2018-05-31) --------------------- * Many improvements and bug fixes `0.3.0`_ (2017-03-19) --------------------- * Initial public release, versions 0.1.0 and 0.2.0 have been skipped to miminize interference when publishing to PyPi .. _0.3.0: https://github.com/benkonrath/transip-api/commit/73925ff .. _0.4.0: https://github.com/benkonrath/transip-api/compare/0.3.0...0.4.0 .. _0.4.1: https://github.com/benkonrath/transip-api/compare/0.4.0...0.4.1 .. _1.0.0: https://github.com/benkonrath/transip-api/compare/0.4.1...v1.0.0 .. _1.0.1: https://github.com/benkonrath/transip-api/compare/v1.0.0...v1.0.1 .. _2.0.0: https://github.com/benkonrath/transip-api/compare/v1.0.1...v2.0.0 transip-api-2.0.0/CONTRIBUTING.rst000066400000000000000000000054441344345634200164200ustar00rootroot00000000000000Contribute ========== This project uses git & python. Setup ----- In order to contribute, please start by making your own fork_ of this repository, and proceed to clone your own nifty fork to your local machine. Isolating the Python environment with virtualenv_ is recommended. Use the following commands to set up a development environment within the Git workspace: .. code-block:: bash $ virtualenv . $ . bin/activate (transip-api) $ pip install -r dev_requirements.txt Or by using virtualenvwrapper_: .. code-block:: bash $ mkvirtualenv transip-api $ cd /path/to/clone $ setvirtualenvproject Proceed to using pip to install all the dependencies .. code-block:: bash $ pip install -r dev_requirements.txt Pull-Request ------------ Please make sure that you make a separate branch for the changes you propose. Subsequent commits to the same branch as the Pull-Request originated from will be picked up by GitHub and added to the Pull-Request. This is quite handy to change things when there are comments about the changeset, but can be annoying if not taken into account. If you make a Pull- Request from your develop branch and you continue developing, all new commits get added to the Pull-Request, which is clearly not wanted. Testing & Code-quality ---------------------- This project uses `unittest` to automatically test the software. Every Pull Request should contain tests, unless it is clear why they are not needed. (e.g. document change only, changes that don't change behaviour.) To ensure consistent code, pylint has been enabled for this project. Included is a `.pylintrc` file, with configuration for this project. To run tests & pylint you can run these two commands .. code-block:: bash $ nosetests --rednose --with-coverage --cover-package=transip $ pylint --rcfile=.pylintrc transip .. note:: pylint configuration is not set in stone. Change the configuration if you feel the need to do so. Please do explain the reason for changing the configuration in the Pull-Request. .. warning:: Bugfixes should add a test that fails with the bug unfixed, but passes with the bux fixed. TravisCI -------- When a Pull-Request is made, TravisCI_ will automatically pick it up and test it using the settings from .travis.yml. The results will be made available both on GitHub with the Pull-Request, as on the specific page for this repository at TravisCI_: https://travis-ci.org/mhogerheijde/transip-api. If anything fails, you can see the specifics about the failure there. Obviously, Pull-Request that fail the test will not be merged. .. _virtualenv: https://github.com/pypa/virtualenv .. _virtualenvwrapper: https://github.com/bernardofire/virtualenvwrapper .. _fork: https://github.com/goabout/goabout-backend/fork .. _TravisCI: https://travis-ci.org/ transip-api-2.0.0/LICENSE000066400000000000000000000021571344345634200147620ustar00rootroot00000000000000MIT License Copyright (c) 2013 Go About B.V. Copyright (c) 2016, 2017 Ben Konrath and individual contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. transip-api-2.0.0/README.rst000066400000000000000000000070561344345634200154470ustar00rootroot00000000000000=========== TransIP API =========== |Build Status| |Docs Status| .. |Build Status| image:: https://travis-ci.org/benkonrath/transip-api.svg?branch=master :target: https://travis-ci.org/benkonrath/transip-api :alt: Build Status .. |Docs Status| image:: https://readthedocs.org/projects/transip-api/badge/?version=latest :target: https://transip-api.readthedocs.io/en/latest/?badge=latest :alt: Documentation Status This library aims to implement the `TransIP API`_ in Python. Quick Start =========== Prerequisite ------------ * Make sure you have an account at TransIP_ * *Enable* the API (https://www.transip.nl/cp/mijn-account/#api) * Whitelist your IP. * Generate a new key-pair. + Copy-paste the private key into a file. + Put the private key in a file called ``decrypted_key`` beside this ``README.rst`` file. Setup ----- .. code-block:: $ python setup.py install Example ------- The command-line interpreter doesn't do much yet. By default it does a getDomainNames() call, but with the '-u' option it's also possible to add or update DNS records. When calling it with '-h', it will show all available options. .. code-block:: $ transip-api [example.com, example.org, example.net] $ transip-api -h usage: transip-api [-h] [-l LOGINNAME] [-s] [-a] [-u] [-d] [--domain-name DOMAIN_NAME] [--entry-name ENTRY_NAME] [--entry-expire ENTRY_EXPIRE] [--entry-type ENTRY_TYPE] [--entry-content ENTRY_CONTENT] [--api-key PRIVATE_KEY_FILE] optional arguments: -h, --help show this help message and exit -l LOGINNAME, --login-name LOGINNAME TransIP username -s, --show-dns-entries show all DNS entries for a domain -a, --add-dns-entry add an entry in the DNS -u, --update-dns-entry update an entry in the DNS -d, --delete-dns-entry delete an entry in the DNS --domain-name DOMAIN_NAME domain name to use --entry-name ENTRY_NAME name of the DNS entry --entry-expire ENTRY_EXPIRE expire time of the DNS entry --entry-type ENTRY_TYPE type of the DNS entry --entry-content ENTRY_CONTENT content of the DNS entry --api-key PRIVATE_KEY_FILE TransIP private key Example of adding/updating a record: .. code-block:: $ transip-api -l githubuser -u --api-key privatekey --domain-name example.com --entry-name testentry --entry-expire 86400 --entry-type A --entry-content 127.0.0.1 Request finished successfully. Documentation ============= Further documentation can be found in the ``docs`` directory, or on https://transip-api.readthedocs.io/en/latest/. .. _virtualenv: http://virtualenv.org/ .. _TransIP: https://www.transip.nl/cp/ .. _`TransIP API`: https://www.transip.eu/transip/api/ FAQ === Question: When using the library I get SSL errors such as: .. code-block:: urllib2.URLError: Answer: The `suds` library has fairly limited SSL support which is dependent on the Python version, to work around this the `suds_requests` library can be used which replaces `urllib2` with the `requests` library. Additionally the `requests` library automatically pools connections which makes the library slightly faster to use. To install: .. code-block:: pip install suds_requests transip-api-2.0.0/dev_requirements.txt000066400000000000000000000001141344345634200200660ustar00rootroot00000000000000bpython nose rednose mock coverage sphinx suds-jurko rsa pylint==1.9.2 -e . transip-api-2.0.0/docs/000077500000000000000000000000001344345634200147005ustar00rootroot00000000000000transip-api-2.0.0/docs/Makefile000066400000000000000000000011041344345634200163340ustar00rootroot00000000000000# Minimal makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build SOURCEDIR = . BUILDDIR = _build # Put it first so that "make" without argument is like "make help". help: @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) .PHONY: help Makefile # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)transip-api-2.0.0/docs/api.rst000066400000000000000000000024611344345634200162060ustar00rootroot00000000000000API === .. module:: transip This part of the documentation lists the full API reference of all public classes and functions. Client ------ .. autoclass:: transip.client.Client :members: Services -------- .. autoclass:: transip.service.domain.DomainService :members: .. autoclass:: transip.service.haip.HaipService :members: .. autoclass:: transip.service.vps.VpsService :members: .. autoclass:: transip.service.webhosting.WebhostingService :members: Objects ------- .. autoclass:: transip.service.objects.DnsEntry :members: .. autoclass:: transip.service.objects.Domain :members: .. autoclass:: transip.service.objects.Nameserver :members: .. autoclass:: transip.service.objects.WhoisContact :members: .. autoclass:: transip.service.objects.DomainBranding :members: .. autoclass:: transip.service.objects.WebhostingPackage :members: .. autoclass:: transip.service.objects.WebHost :members: .. autoclass:: transip.service.objects.MailBox :members: .. autoclass:: transip.service.objects.MailForward :members: .. autoclass:: transip.service.objects.Tld :members: .. autoclass:: transip.service.objects.DomainAction :members: .. autoclass:: transip.service.objects.WhoisContact :members: .. autoclass:: transip.service.objects.DomainCheckResult :members: transip-api-2.0.0/docs/cli.rst000066400000000000000000000036331344345634200162060ustar00rootroot00000000000000Command-line interpreter ======================== The transip-api includes a command-line interpreter (CLI) that doesn't do much yet. By default it does a `getDomainNames()` call, but with the `-u` option it's also possible to add or update DNS records. When calling it with the `-h`, it will show all available options. .. code-block:: bash $ transip-api [example.com, example.org, example.net] $ transip-api -h usage: transip-api [-h] [-l LOGINNAME] [-s] [-a] [-u] [-d] [--domain-name DOMAIN_NAME] [--entry-name ENTRY_NAME] [--entry-expire ENTRY_EXPIRE] [--entry-type ENTRY_TYPE] [--entry-content ENTRY_CONTENT] [--api-key PRIVATE_KEY_FILE] optional arguments: -h, --help show this help message and exit -l LOGINNAME, --login-name LOGINNAME TransIP username -s, --show-dns-entries show all DNS entries for a domain -a, --add-dns-entry add an entry in the DNS -u, --update-dns-entry update an entry in the DNS -d, --delete-dns-entry delete an entry in the DNS --domain-name DOMAIN_NAME domain name to use --entry-name ENTRY_NAME name of the DNS entry --entry-expire ENTRY_EXPIRE expire time of the DNS entry --entry-type ENTRY_TYPE type of the DNS entry --entry-content ENTRY_CONTENT content of the DNS entry --api-key PRIVATE_KEY_FILE TransIP private key Example of adding/updating a record: .. code-block:: bash $ transip-api -l githubuser -u --api-key privatekey --domain-name example.com --entry-name testentry --entry-expire 86400 --entry-type A --entry-content 127.0.0.1 Request finished successfully. transip-api-2.0.0/docs/conf.py000066400000000000000000000127101344345634200162000ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # Configuration file for the Sphinx documentation builder. # # This file does only contain a selection of the most common options. For a # full list see the documentation: # http://www.sphinx-doc.org/en/master/config # -- Path setup -------------------------------------------------------------- # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # # import os # import sys # sys.path.insert(0, os.path.abspath('.')) from transip import __version__ # -- Project information ----------------------------------------------------- project = u'transip-api' copyright = u'2018, Go About B.V.' author = u'Go About B.V.' # The short X.Y version version = __version__ # The full version, including alpha/beta/rc tags release = version # -- General configuration --------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. # # needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ 'sphinx.ext.autodoc', 'sphinx.ext.intersphinx', ] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # # source_suffix = ['.rst', '.md'] source_suffix = '.rst' # The master toctree document. master_doc = 'index' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. language = None # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. exclude_patterns = [u'_build', 'Thumbs.db', '.DS_Store'] # The name of the Pygments (syntax highlighting) style to use. pygments_style = None # -- Options for HTML output ------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # html_theme = 'alabaster' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. # # html_theme_options = {} # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # Custom sidebar templates, must be a dictionary that maps document names # to template names. # # The default sidebars (for documents that don't match any pattern) are # defined by theme itself. Builtin themes are using these templates by # default: ``['localtoc.html', 'relations.html', 'sourcelink.html', # 'searchbox.html']``. # # html_sidebars = {} # -- Options for HTMLHelp output --------------------------------------------- # Output file base name for HTML help builder. htmlhelp_basename = 'transip-apidoc' # -- Options for LaTeX output ------------------------------------------------ latex_elements = { # The paper size ('letterpaper' or 'a4paper'). # # 'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). # # 'pointsize': '10pt', # Additional stuff for the LaTeX preamble. # # 'preamble': '', # Latex figure (float) alignment # # 'figure_align': 'htbp', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ (master_doc, 'transip-api.tex', u'transip-api Documentation', u'Go About B.V.', 'manual'), ] # -- Options for manual page output ------------------------------------------ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ (master_doc, 'transip-api', u'transip-api Documentation', [author], 1) ] # -- Options for Texinfo output ---------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ (master_doc, 'transip-api', u'transip-api Documentation', author, 'transip-api', 'One line description of project.', 'Miscellaneous'), ] # -- Options for Epub output ------------------------------------------------- # Bibliographic Dublin Core info. epub_title = project # The unique identifier of the text. This can be a ISBN number # or the project homepage. # # epub_identifier = '' # A unique identification for the text. # # epub_uid = '' # A list of files that should not be packed into the epub file. epub_exclude_files = ['search.html'] # -- Extension configuration ------------------------------------------------- # -- Options for intersphinx extension --------------------------------------- # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = {'https://docs.python.org/': None} transip-api-2.0.0/docs/contrib.rst000066400000000000000000000000411344345634200170650ustar00rootroot00000000000000.. include:: ../CONTRIBUTING.rst transip-api-2.0.0/docs/index.rst000066400000000000000000000022501344345634200165400ustar00rootroot00000000000000Welcome to transip-api's documentation! ======================================= This library aims to implement the TransIP API in Python. Here is an example of a simple Python program: .. code-block:: python from transip.service.vps import VpsService PRIVATE_KEY = ''' -----BEGIN PRIVATE KEY----- ... -----END PRIVATE KEY----- ''' # You can specify the private key directly or supply the path to the private # key file. The private_key_file will default to `decrypted_key`. client = VpsService('accountname', private_key_file='/path/to/decrypted_key') client = VpsService('accountname', private_key=PRIVATE_KEY) # Order a Vps without addons: client.order_vps('vps-bladevps-x1', None, 'ubuntu-18.04', 'vps-name') You can get the library directly from PyPI:: pip install transip-api Documentation ------------- This part of the documentation guides you through all of the library's usage patterns. .. toctree:: :maxdepth: 2 quickstart cli api Miscellaneous Pages ------------------- .. toctree:: :maxdepth: 2 contrib license Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` transip-api-2.0.0/docs/license.rst000066400000000000000000000001621344345634200170530ustar00rootroot00000000000000License ======= Transip-api is licensed under a MIT License. License Text ------------ .. include:: ../LICENSE transip-api-2.0.0/docs/make.bat000066400000000000000000000014231344345634200163050ustar00rootroot00000000000000@ECHO OFF pushd %~dp0 REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set SOURCEDIR=. set BUILDDIR=_build if "%1" == "" goto help %SPHINXBUILD% >NUL 2>NUL if errorlevel 9009 ( echo. echo.The 'sphinx-build' command was not found. Make sure you have Sphinx echo.installed, then set the SPHINXBUILD environment variable to point echo.to the full path of the 'sphinx-build' executable. Alternatively you echo.may add the Sphinx directory to PATH. echo. echo.If you don't have Sphinx installed, grab it from echo.http://sphinx-doc.org/ exit /b 1 ) %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% goto end :help %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% :end popd transip-api-2.0.0/docs/quickstart.rst000066400000000000000000000034621344345634200176310ustar00rootroot00000000000000Quickstart ========== .. currentmodule:: transip-api You can get the library directly from PyPI:: pip install transip-api The installation into a :ref:`virtualenv` is heavily recommended. .. _virtualenv: virtualenv ---------- Virtualenv is probably what you want to use for developing Python applications. If you are on Mac OS X or Linux, chances are the one of the following two commands will work for you:: $ sudo easy_install virtualenv or even better:: $ sudo pip install virtualenv One of these will probably install virtualenv on your system. Maybe it's even in your package manager. If you use Ubuntu, try:: $ sudo apt-get install python-virtualenv If you are on Windows (or none of the above methods worked) you must install ``pip`` first. For more information about this, see `installing pip`_. Once you have it installed, run the ``pip`` command from above, but without the ``sudo`` prefix. .. _installing pip: https://pip.readthedocs.io/en/latest/installing.html Once you have virtualenv installed, just fire up a shell and create your own environment. You could create a project folder and a `venv` folder within:: $ mkdir myproject $ cd myproject $ virtualenv venv Now, whenever you want to work on a project, you only have to activate the corresponding environment. On Mac OS X and Linux, do the following:: $ . venv/bin/activate If you are on Windows, use the following command:: $ venv\scripts\activate Either way, you should now be using your virtualenv (notice how the promt of you shell has changed to show the active environment). And if you want to exit your virtualenv, use the following command:: $ deactivate Enter the following command to get transip-api installed in your virtualenv:: $ pip install virtualenv A few seconds later and your are good to go. transip-api-2.0.0/setup.cfg000066400000000000000000000000321344345634200155640ustar00rootroot00000000000000[bdist_wheel] universal=1 transip-api-2.0.0/setup.py000066400000000000000000000033341344345634200154650ustar00rootroot00000000000000#!/usr/bin/env python import os import re import codecs from setuptools import setup def read(*parts): filename = os.path.join(os.path.dirname(__file__), *parts) with codecs.open(filename, encoding='utf-8') as fp: return fp.read() def find_version(*file_paths): version_file = read(*file_paths) version_match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]", version_file, re.M) if version_match: return version_match.group(1) raise RuntimeError("Unable to find version string.") setup( name='transip', version=find_version('transip', '__init__.py'), author='Go About B.V.', author_email='tech@goabout.com', maintainer='Ben Konrath', maintainer_email='ben@bagu.org', license='MIT', description='TransIP API Connector', long_description=read('README.rst'), url='https://github.com/benkonrath/transip-api', packages=['transip', 'transip.service'], include_package_data=True, zip_safe=False, platforms=['all'], test_suite='tests', entry_points={ 'console_scripts': [ 'transip-api=transip.transip_cli:main', ], }, install_requires=[ 'requests', 'cryptography', 'suds-jurko', ], classifiers=[ 'Development Status :: 4 - Beta', 'Intended Audience :: Developers', 'License :: OSI Approved :: MIT License', 'Operating System :: OS Independent', 'Programming Language :: Python', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Topic :: Utilities', ], ) transip-api-2.0.0/test000077500000000000000000000003041344345634200146520ustar00rootroot00000000000000#!/bin/zsh find . -name \*.pyc -delete nosetests --rednose --with-coverage --cover-package=transip echo "------------------------------------------------------" pylint --rcfile=.pylintrc transip transip-api-2.0.0/test_key000066400000000000000000000015671344345634200155330ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIICWwIBAAKBgQClVVqWbw+RkyIG+K1pm6RNkc1yF91IRl6tlL6cRRRkK9zxZAdc QPGh0XUsz6HrZi7dxRz9XnTK58oIxk+NykeJVve1TTV5rY3hIxxPM+TgF5yNBhgZ /+F90a/j7P5nHYPL2DJlmUOny5MslhaeVRRaTBnTJonmXxbMB38MQyGefwIDAQAB AoGAbl4lI8kt5msGywqUkKxCqTmMoP5HTKkVKODjwWPn8drKGiZBN5du9iviAbD1 kTPcU1TzPjwg0RacavEfSDLhPz0eRdPreZHht9Mw2yBOBL0yhoxK1/JfygqWhI1p cDoxI5J4D0K7QTMdVgvdJ3/DCRxvuCGedcgBBOTEF9BGzkkCQQDbYNdpYVcIlzds VwVWll2zz9rKyxa+N5zbZ0MpFAd3ayEV6EsZTuWp8fk4amUuVsMKHzTEp1WGMuz7 Ok28UEtVAkEAwO7l4c7fNXpWJfhCd5gOr4Xqzjyz+O+h/z06c33gRi/mLBIAFMyc dPPq2ihfrDMsQle/sv11DjFzr0mLhDLKgwJAHgoetRFdJ5H9RtqLopWocwzNOuOg U5+t3OVA7wkNFK8YsrVCQ07oZ+L4a182R6gdwO8Q/LSlI2EpziTnrBeamQJAH3tc G5qsJYfO4uc9wVIYo1+QzxJss6Q2pPWSwiG6JPnP70UIqlww84yRuAN6iRjYkgLL jyN4pFZBcErp7ypyjQJADdd5QlvK1R1U2mNbDA/Ig8pwJ9/akChMH5ibCKGujQtZ ebs5fO2jPTlkavfWivL3VjkKoF4WTQZq5ly8Ja2PgA== -----END RSA PRIVATE KEY----- transip-api-2.0.0/tests/000077500000000000000000000000001344345634200151125ustar00rootroot00000000000000transip-api-2.0.0/tests/__init__.py000066400000000000000000000000001344345634200172110ustar00rootroot00000000000000transip-api-2.0.0/tests/service_tests/000077500000000000000000000000001344345634200177745ustar00rootroot00000000000000transip-api-2.0.0/tests/service_tests/__init__.py000066400000000000000000000000001344345634200220730ustar00rootroot00000000000000transip-api-2.0.0/tests/service_tests/test_dns.py000066400000000000000000000010121344345634200221630ustar00rootroot00000000000000import unittest from transip.service.objects import DnsEntry class TestDnsEntry(unittest.TestCase): def testEquality(self): dns_entry_one = DnsEntry('@', 300, DnsEntry.TYPE_A, '8.8.8.8') dns_entry_two = DnsEntry('@', 300, DnsEntry.TYPE_A, '8.8.8.8') self.assertEqual(dns_entry_one, dns_entry_two) dns_entry_two.expire = 600 self.assertEqual(dns_entry_one, dns_entry_two) dns_entry_two.content = '127.0.0.1' self.assertNotEqual(dns_entry_one, dns_entry_two) transip-api-2.0.0/tests/service_tests/test_domain.py000066400000000000000000000231111344345634200226520ustar00rootroot00000000000000import unittest from transip.service import DomainService from transip.client import MODE_RO, MODE_RW from transip.service.objects import DnsEntry try: from unittest.mock import Mock, patch except ImportError: from mock import patch, Mock class TestDomainService(unittest.TestCase): @patch('transip.client.SudsClient') def setUp(self, mock_client): super(TestDomainService, self).setUp() self.service = DomainService(login='sundayafternoon') self.service.build_cookie = Mock(return_value={"cookie": "value"}) self.service.update_cookie = Mock() self.i = mock_client.return_value def set_return_value(self, method, value): getattr(self.i.service, method).return_value = value def _generic_test(self, soap_method, method, result, parameters=(), mode=MODE_RO): self.set_return_value(soap_method, result) # CALL soap_result = getattr(self.service, method)(*parameters) # VERIFY self.service.build_cookie.assert_called_with(mode=mode, method=soap_method, parameters=parameters) self.service.update_cookie.assert_called_with({"cookie": "value"}) getattr(self.i.service, soap_method).assert_called_with(*parameters) self.assertEqual(soap_result, result) def test_constructor(self): # CALL ds = DomainService(login='sundayafternoon') # VERIFY self.assertEqual(ds.url, 'https://api.transip.nl/wsdl/?service=DomainService') @patch('transip.client.SudsClient') def test_get_domains(self, mock_client): # SETUP ds = DomainService('sundayafternoon') ds.build_cookie = Mock(return_value={"cookie": "value"}) ds.update_cookie = Mock() i = mock_client.return_value i.service.getDomainNames.return_value = ['domain1', 'domain2'] # CALL result = ds.get_domain_names() # VERIFY ds.build_cookie.assert_called_with(mode=MODE_RO, method='getDomainNames', parameters=()) ds.update_cookie.assert_called_with({"cookie": "value"}) i.service.getDomainNames.assert_called_with() self.assertEqual(result, ['domain1', 'domain2']) @patch('transip.client.SudsClient') def test_get_info(self, mock_client): # SETUP ds = DomainService(login='sundayafternoon') ds.build_cookie = Mock(return_value={"cookie": "value"}) ds.update_cookie = Mock() i = mock_client.return_value getinfo_result = Mock() getinfo_result.dnsEntries = [DnsEntry('testentry', 86400, DnsEntry.TYPE_A, '127.0.0.1')] i.service.getInfo.return_value = getinfo_result # CALL result = ds.get_info('example.com') # VERIFY ds.build_cookie.assert_called_with(mode=MODE_RO, method='getInfo', parameters=['example.com']) ds.update_cookie.assert_called_with({"cookie": "value"}) i.service.getInfo.assert_called_with('example.com') self.assertEqual(result, getinfo_result) @patch('transip.client.SudsClient') def test_set_dns_entries(self, mock_client): # SETUP ds = DomainService('sundayafternoon') ds.build_cookie = Mock(return_value={"cookie": "value"}) ds.update_cookie = Mock() i = mock_client.return_value i.service.setDnsEntries.return_value = None dns_entry = DnsEntry('testentry', 86400, DnsEntry.TYPE_A, '127.0.0.1') # CALL result = ds.set_dns_entries('domain1', [dns_entry, ]) # VERIFY ds.build_cookie.assert_called_with(mode=MODE_RW, method='setDnsEntries', parameters=('domain1', [dns_entry, ])) ds.update_cookie.assert_called_with({"cookie": "value"}) i.service.setDnsEntries.assert_called_with('domain1', [dns_entry, ]) def test_batch_check_availability(self): self._generic_test( soap_method='batchCheckAvailability', method='batch_check_availability', result='mock', parameters=(['example.com', 'example.nl'],), mode=MODE_RO ) with self.assertRaises(ValueError): self._generic_test( soap_method='batchCheckAvailability', method='batch_check_availability', result='mock', parameters=(['example.com', 'example.nl'] * 11,), mode=MODE_RO ) def test_check_availability(self): self._generic_test( soap_method='checkAvailability', method='check_availability', result='mock', parameters=('example.com',), mode=MODE_RO ) def test_get_whois(self): self._generic_test( soap_method='getWhois', method='get_whois', result='mock', parameters=('example.com',), mode=MODE_RO ) def test_get_domain_names(self): self._generic_test( soap_method='getDomainNames', method='get_domain_names', result=['mock', 'mock2'], mode=MODE_RO ) def test_batch_get_info(self): self._generic_test( soap_method='batchGetInfo', method='batch_get_info', result=['mock', 'mock2'], parameters=('example.com',), mode=MODE_RO ) def test_get_auth_code(self): self._generic_test( soap_method='getAuthCode', method='get_auth_code', result='string', parameters=('example.com',), mode=MODE_RO ) def test_get_is_locked(self): self._generic_test( soap_method='getIsLocked', method='get_is_locked', result=True, parameters=('example.com',), mode=MODE_RO ) def test_register(self): self._generic_test( soap_method='register', method='register', result='string', parameters=('example.com',), mode=MODE_RW ) def test_cancel(self): self._generic_test( soap_method='cancel', method='cancel', result='string', parameters=('example.com', 'domain'), mode=MODE_RW ) def test_transfer_with_owner_change(self): self._generic_test( soap_method='transferWithOwnerChange', method='transfer_with_owner_change', result='string', parameters=('example.com', 'authcode'), mode=MODE_RW ) def test_transfer_without_owner_change(self): self._generic_test( soap_method='transferWithoutOwnerChange', method='transfer_without_owner_change', result='string', parameters=('example.com', 'authcode'), mode=MODE_RW ) def test_set_nameservers(self): self._generic_test( soap_method='setNameservers', method='set_nameservers', result='string', parameters=('example.com', 'nameservers'), mode=MODE_RW ) def test_set_lock(self): self._generic_test( soap_method='setLock', method='set_lock', result='string', parameters=('example.com',), mode=MODE_RW ) def test_unset_lock(self): self._generic_test( soap_method='unsetLock', method='unset_lock', result='string', parameters=('example.com',), mode=MODE_RW ) def test_set_owner(self): self._generic_test( soap_method='setOwner', method='set_owner', result='string', parameters=('example.com', 'registrant_whois_contact'), mode=MODE_RW ) def test_set_contacts(self): self._generic_test( soap_method='setContacts', method='set_contacts', result='string', parameters=('example.com', 'contacts'), mode=MODE_RW ) def test_get_all_tld_infos(self): self._generic_test( soap_method='getAllTldInfos', method='get_all_tld_infos', result='string', mode=MODE_RO ) def test_get_tld_info(self): self._generic_test( soap_method='getTldInfo', method='get_tld_info', result='string', parameters=('.com',), mode=MODE_RO ) def test_get_current_domain_action(self): self._generic_test( soap_method='getCurrentDomainAction', method='get_current_domain_action', result='string', parameters=('example.com',), mode=MODE_RO ) def test_retry_current_domain_action_with_new_data(self): self._generic_test( soap_method='retryCurrentDomainActionWithNewData', method='retry_current_domain_action_with_new_data', result='string', parameters=('example.com',), mode=MODE_RO ) def test_retry_transfer_with_different_auth_code(self): self._generic_test( soap_method='retryTransferWithDifferentAuthCode', method='retry_transfer_with_different_auth_code', result='string', parameters=('example.com', 'new_auth_code'), mode=MODE_RO ) def test_cancel_domain_action(self): self._generic_test( soap_method='cancelDomainAction', method='cancel_domain_action', result='string', parameters=('example.com',), mode=MODE_RO )transip-api-2.0.0/tests/service_tests/test_vps.py000066400000000000000000000034171344345634200222220ustar00rootroot00000000000000import unittest from transip.service import VpsService from transip.client import MODE_RO, MODE_RW try: from unittest.mock import Mock, patch except ImportError: from mock import patch, Mock class TestVPSService(unittest.TestCase): def testConstructor(self): # CALL vs = VpsService(login='sundayafternoon') # VERIFY self.assertEqual(vs.url, 'https://api.transip.nl/wsdl/?service=VpsService') @patch('transip.client.SudsClient') def testGetVpses(self, mock_client): # SETUP vs = VpsService(login='sundayafternoon') vs.build_cookie = Mock(return_value={"cookie":"value"}) vs.update_cookie = Mock() i = mock_client.return_value i.service.getVpses.return_value = ['vps1', 'vps2'] # CALL result = vs.get_vpses() # VERIFY vs.build_cookie.assert_called_with(mode=MODE_RO, method='getVpses') vs.update_cookie.assert_called_with({"cookie": "value"}) i.service.getVpses.assert_called_with() self.assertEqual(result, [ 'vps1', 'vps2' ]) @patch('transip.client.SudsClient') def testSetCustomerLock(self, mock_client): # SETUP vs = VpsService(login='sundayafternoon') vs.build_cookie = Mock(return_value={"cookie":"value"}) vs.update_cookie = Mock() i = mock_client.return_value i.service.setCustomerLock.return_value = None # CALL result = vs.set_customer_lock(vps_name='test',enabled=1) # VERIFY vs.build_cookie.assert_called_with(mode=MODE_RW, method='setCustomerLock', parameters=['test',1]) vs.update_cookie.assert_called_with({"cookie": "value"}) i.service.setCustomerLock.assert_called_with('test', 1) self.assertEqual(result, None) transip-api-2.0.0/tests/service_tests/test_webhosting.py000066400000000000000000000105721344345634200235630ustar00rootroot00000000000000import unittest from transip.client import MODE_RO, MODE_RW from transip.service.objects import WebHost, MailBox, MailForward from transip.service.webhosting import WebhostingService try: from unittest.mock import Mock, patch except ImportError: from mock import patch, Mock class TestWebhostingService(unittest.TestCase): @patch('transip.client.SudsClient') def setUp(self, mock_client): self.service = WebhostingService(login='sundayafternoon') self.service.build_cookie = Mock(return_value={"cookie": "value"}) self.service.update_cookie = Mock() self.i = mock_client.return_value def set_return_value(self, method, value): getattr(self.i.service, method).return_value = value def _generic_test(self, soap_method, method, result, parameters=(), mode=MODE_RO): self.set_return_value(soap_method, result) # CALL soap_result = getattr(self.service, method)(*parameters) # VERIFY self.service.build_cookie.assert_called_with(mode=mode, method=soap_method, parameters=parameters) self.service.update_cookie.assert_called_with({"cookie": "value"}) getattr(self.i.service, soap_method).assert_called_with(*parameters) self.assertEqual(soap_result, result) def testConstructor(self): vs = WebhostingService(login='sundayafternoon') self.assertEqual(vs.url, 'https://api.transip.nl/wsdl/?service=WebhostingService') def test_available_packages(self): self._generic_test( soap_method='getAvailablePackages', method='get_available_packages', result=['Webhosting s', 'Webhosting l', 'Webhosting xl', 'Email only'] ) def test_webhosting_domain_names(self): self._generic_test( soap_method='getWebhostingDomainNames', method='get_webhosting_domain_names', result=['example.com', 'since we are mocking, the results do not mater'] ) def test_info(self): self._generic_test( soap_method='getInfo', method='get_info', result=WebHost('example.com'), parameters=('example.com', ) ) def test_create_mailbox(self): mailbox = MailBox('info@example.com') self._generic_test( soap_method='createMailBox', method='create_mailbox', result=mailbox, parameters=('info@example.com', mailbox), mode=MODE_RW ) def test_update_mailbox(self): self._generic_test( soap_method='modifyMailBox', method='update_mailbox', result='mock', parameters=('info@example.com', 'mock'), mode=MODE_RW ) def test_delete_mailbox(self): self._generic_test( soap_method='deleteMailBox', method='delete_mailbox', result='mock', parameters=('info@example.com', 'mock'), mode=MODE_RW ) def test_create_mail_forward(self): mail_forward = MailForward('test', 'info@example.com') self._generic_test( soap_method='createMailForward', method='create_mail_forward', result=mail_forward, parameters=('info@example.com', mail_forward), mode=MODE_RW ) def test_update_mail_forward(self): self._generic_test( soap_method='modifyMailForward', method='update_mail_forward', result='mock', parameters=('info@example.com', 'mock'), mode=MODE_RW ) def test_delete_mail_forward(self): self._generic_test( soap_method='deleteMailForward', method='delete_mail_forward', result='mock', parameters=('info@example.com', 'mock'), mode=MODE_RW ) def test_get_available_upgrades(self): self._generic_test( soap_method='getAvailableUpgrades', method='get_available_upgrades', result='mock', parameters=('example.com',), mode=MODE_RO ) def test_set_mailbox_password(self): self._generic_test( soap_method='setMailBoxPassword', method='set_mailbox_password', result='mock', parameters=('example.com', 'mailbox', 'password'), mode=MODE_RW )transip-api-2.0.0/tests/test_client.py000066400000000000000000000141011344345634200177760ustar00rootroot00000000000000# vim: set fileencoding=utf-8 : import unittest import transip from collections import OrderedDict from transip.client import Client, MODE_RO try: from unittest.mock import Mock, patch except ImportError: from mock import patch, Mock class TestClient(unittest.TestCase): @patch('transip.client.SudsClient') def testConstructor(self, mock_client): # CALL c = Client('TestService', login='sundayafternoon') # VERIFY self.assertEqual(c.service_name, 'TestService') self.assertEqual(c.url, 'https://api.transip.nl/wsdl/?service=TestService') @patch('transip.client.SudsClient') def testSignatureIsCorrect(self, mock_client): # SETUP reference1 = 'ZurqqM1HQTWqYb5IOFYEk%2BGw7a2I%2FknIHEw9lJag%2FnHDp3XfZYj%2F89GTjM52x6spJEJtUnUpSZ02DsVoaJlGl4iZEMk0%2FbWcP5ODRJhASHHsznHWfbK3wY5bk2kDjjsaaaVNlNVIWl52tPpHOrWAaca0uaMVLWuM6IP1tdiWsFI%3D' to_sign1 = '__method=getDomainNames&__service=DomainService&__hostname=api.transip.nl&__timestamp=1390235362&__nonce=2e49613c-35b9-4827-a882-8d755504' reference2 = 'ly2K%2BZjs45hMqTsF%2BxwwHeTvqlHHchvLkRokP16EISaukSkOf714bA0QJA7QxipxPQEHyWNoezD5g3vb2OWv38N8U%2BFLGbcpoT89hi2Zsv7B96QBcew8cxvgwdBM0rM8ixYuw%2FyASsG%2BLvyEzo55eXE3st2aAsG5CP1xwQdLG0I%3D' to_sign2 = '__method=getDomainNames&__service=DomainService&__hostname=api.transip.nl&__timestamp=1390236369&__nonce=e0736a8f-fcf4-435f-a7f1-c1d2ccaa' c = Client('foo', login='sundayafternoon', private_key_file='test_key') # CALL signature1 = c._sign(to_sign1) signature2 = c._sign(to_sign2) # VERIFY self.assertEqual(signature1, reference1) self.assertEqual(signature2, reference2) @patch('transip.client.SudsClient') def testBuildSignature(self, mock_client): # SETUP c = Client('foo', login='sundayafternoon') reference = '__method=getDomainNames&__service=DomainService&__hostname=api.transip.nl&__timestamp=123&__nonce=TEST-NONCE' # CALL message = c._build_signature_message('DomainService', 'getDomainNames', 123, 'TEST-NONCE') # VERIFY self.assertEqual(message, reference) @patch('transip.client.SudsClient') def testBuildSignatureWithAdditionalParameters(self, mock_client): # SETUP c = Client('foo', login='sundayafternoon') reference = '0=foo&1=bar&__method=getDomainNames&__service=DomainService&__hostname=api.transip.nl&__timestamp=123&__nonce=TEST-NONCE' additional = ['foo', 'bar'] # CALL message = c._build_signature_message('DomainService', 'getDomainNames', 123, 'TEST-NONCE', additional) # VERIFY self.assertEqual(message, reference) @patch('transip.client.SudsClient') def testBuildSignatureParametersSpecialCharacters(self, mock_client): # SETUP c = Client('foo', login='sundayafternoon') reference = '0=foo%20bar&1=~all&2=%2A.foo&__method=getDomainNames&__service=DomainService&__hostname=api.transip.nl&__timestamp=123&__nonce=TEST-NONCE' additional = ['foo bar', '~all', '*.foo'] # CALL message = c._build_signature_message('DomainService', 'getDomainNames', 123, 'TEST-NONCE', additional) # VERIFY self.assertEqual(message, reference) @patch('uuid.uuid4') @patch('time.time') @patch('transip.client.SudsClient') def testBuildCookies(self, mock_client, mock_time, mock_uuid): # SETUP c = Client('DomainService', login='sundayafternoon', private_key_file='test_key') mock_uuid.return_value = 'MOCKED-NONCE' mock_time.return_value = 123 c._sign = Mock() c._sign.return_value = "MOCKED-SIGNATURE" reference_cookie = { 'login': 'sundayafternoon', 'mode': MODE_RO, 'timestamp': 123, 'nonce': 'MOCKED-NONCE', 'clientVersion': transip.__version__, 'signature':'MOCKED-SIGNATURE' } # CALL cookie = c.build_cookie(mode='readonly', method='getDomainNames') # VERIFY self.maxDiff = None self.assertEqual(cookie, reference_cookie) c._sign.assert_called_with('__method=getDomainNames&__service=DomainService&__hostname=api.transip.nl&__timestamp=123&__nonce=MOCKED-NONCE') @patch('uuid.uuid4') @patch('time.time') @patch('transip.client.SudsClient') def testBuildCookiesWithAdditionalParameters(self, mock_client, mock_time, mock_uuid): # SETUP c = Client('DomainService', login='sundayafternoon', private_key_file='test_key') c._sign = Mock() c._sign.return_value = "MOCKED-SIGNATURE" mock_uuid.return_value = 'MOCKED-NONCE' mock_time.return_value = 123 reference_cookie = { 'login': 'sundayafternoon', 'mode': MODE_RO, 'timestamp': 123, 'nonce': 'MOCKED-NONCE', 'clientVersion': transip.__version__, 'signature':'MOCKED-SIGNATURE' } # CALL cookie = c.build_cookie(mode = 'readonly', method = 'getInfo', parameters=['example.com']) # VERIFY self.maxDiff = None self.assertEqual(cookie, reference_cookie) c._sign.assert_called_with('0=example.com&__method=getInfo&__service=DomainService&__hostname=api.transip.nl&__timestamp=123&__nonce=MOCKED-NONCE') @patch('transip.client.ImportDoctor') @patch('transip.client.Import') @patch('transip.client.SudsClient') def testSoapClientIsInitialised(self, mock_client, mock_import, mock_import_doctor): # SETUP c = Client('DomainService', login='loginname') # VERIFY self.assertEqual(c.soap_client, mock_client()) @patch('transip.client.SudsClient') def testUpdateCookie(self, mock_client): # SETUP c = Client('Foo', login='sundayafternoon') cookies = OrderedDict() cookies['foo'] = 'bar' cookies['baz'] = 'qux' # CALL c.update_cookie(cookies) # VERIFY c.soap_client.set_options.assert_called_with(headers={'Cookie': 'foo=bar;baz=qux'}) transip-api-2.0.0/transip/000077500000000000000000000000001344345634200154305ustar00rootroot00000000000000transip-api-2.0.0/transip/__init__.py000066400000000000000000000003111344345634200175340ustar00rootroot00000000000000""" TransIP API Connector A python implementation for usage of the API for TransIP. For usage of the API itself, please see https://www.transip.eu/transip/api/ """ __version__ = '2.0.0' transip-api-2.0.0/transip/client.py000066400000000000000000000150071344345634200172630ustar00rootroot00000000000000""" The Client class, handling direct communication with the API """ from __future__ import print_function import base64 import os import time import uuid from collections import OrderedDict from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric import padding from suds.client import Client as SudsClient from suds.sudsobject import Object as SudsObject from suds.xsd.doctor import Import, ImportDoctor from . import __version__ try: from urllib.parse import urlencode, quote_plus except ImportError: from urllib import urlencode, quote_plus try: import suds_requests except ImportError: suds_requests = None URI_TEMPLATE = 'https://{}/wsdl/?service={}' MODE_RO = 'readonly' MODE_RW = 'readwrite' def convert_value(value): """ None and boolean values are not accepted by the Transip API. This method converts - None and False to an empty string, - True to 1 """ if isinstance(value, bool): return 1 if value else '' if not value: return '' return value class Client(object): """ A client-base class, for other classes to base their service implementation on. Contains methods to set and sign cookie and to retrieve the correct WSDL for specific parts of the TransIP API. Note: You either need to supply a private_key or a private_key_file. Args: service_name (str): Name of the service. login (str): The TransIP username. private_key (str, optional): The content of the private key for accessing the TransIP API. private_key_file (str, optional): Path the the private key for accesing the TransIP API. Defaults to 'decrypted_key'. endpoint (str): The TransIP API endpoint. Defaults to 'api.transip.nl'. """ def __init__(self, service_name, login, private_key=None, private_key_file='decrypted_key', endpoint='api.transip.nl'): self.service_name = service_name self.login = login self.private_key = private_key self.private_key_file = private_key_file self.endpoint = endpoint self.url = URI_TEMPLATE.format(endpoint, service_name) imp = Import('http://schemas.xmlsoap.org/soap/encoding/') doc = ImportDoctor(imp) suds_kwargs = dict() if suds_requests: suds_kwargs['transport'] = suds_requests.RequestsTransport() self.soap_client = SudsClient(self.url, doctor=doc, **suds_kwargs) def _sign(self, message): """ Uses the decrypted private key to sign the message. """ if self.private_key: keydata = self.private_key elif os.path.exists(self.private_key_file): with open(self.private_key_file) as private_key: keydata = private_key.read() else: raise RuntimeError('The private key does not exist.') private_key = serialization.load_pem_private_key( str.encode(keydata), password=None, backend=default_backend() ) signature = private_key.sign( str.encode(message), padding.PKCS1v15(), hashes.SHA512(), ) signature = base64.b64encode(signature) signature = quote_plus(signature) return signature def _build_signature_message(self, service_name, method_name, timestamp, nonce, additional=None): """ Builds the message that should be signed. This message contains specific information about the request in a specific order. """ if additional is None: additional = [] sign = OrderedDict() # Add all additional parameters first for index, value in enumerate(additional): if isinstance(value, list): for entryindex, entryvalue in enumerate(value): if isinstance(entryvalue, SudsObject): for objectkey, objectvalue in entryvalue: objectvalue = convert_value(objectvalue) sign[str(index) + '[' + str(entryindex) + '][' + objectkey + ']'] = objectvalue elif isinstance(value, SudsObject): for entryindex, entryvalue in value: key = str(index) + '[' + str(entryindex) + ']' sign[key] = convert_value(entryvalue) else: sign[index] = convert_value(value) sign['__method'] = method_name sign['__service'] = service_name sign['__hostname'] = self.endpoint sign['__timestamp'] = timestamp sign['__nonce'] = nonce return urlencode(sign) \ .replace('%5B', '[') \ .replace('%5D', ']') \ .replace('+', '%20') \ .replace('%7E', '~') # Comply with RFC3989. This replacement is also in TransIP's sample PHP library. def update_cookie(self, cookies): """ Updates the cookie for the upcoming call to the API. """ temp = [] for k, val in cookies.items(): temp.append("%s=%s" % (k, val)) cookiestring = ';'.join(temp) self.soap_client.set_options(headers={'Cookie': cookiestring}) def build_cookie(self, method, mode, parameters=None): """ Build a cookie for the request. Keyword arguments: method -- the method to be called on the service. mode -- Read-only (MODE_RO) or read-write (MODE_RW) """ timestamp = int(time.time()) nonce = str(uuid.uuid4())[:32] message_to_sign = self._build_signature_message( service_name=self.service_name, method_name=method, timestamp=timestamp, nonce=nonce, additional=parameters ) signature = self._sign(message_to_sign) cookies = { "nonce": nonce, "timestamp": timestamp, "mode": mode, "clientVersion": __version__, "login": self.login, "signature": signature } return cookies def _simple_request(self, method, *args, **kwargs): """ Helper method to create a request in a DRY way """ cookie = self.build_cookie(mode=kwargs.get('mode', MODE_RO), method=method, parameters=args) self.update_cookie(cookie) return getattr(self.soap_client.service, method)(*args) transip-api-2.0.0/transip/service/000077500000000000000000000000001344345634200170705ustar00rootroot00000000000000transip-api-2.0.0/transip/service/__init__.py000066400000000000000000000002741344345634200212040ustar00rootroot00000000000000""" Module containing all the different services that the TrapsIP API has to offer. """ from transip.service.domain import DomainService from transip.service.vps import VpsService transip-api-2.0.0/transip/service/domain.py000066400000000000000000000170371344345634200207210ustar00rootroot00000000000000# pylint: disable=too-many-public-methods """ The connector to Domain related API calls """ from transip.client import Client, MODE_RO, MODE_RW from transip.service.objects import DnsEntry class DomainService(Client): """ Representation of the DomainService API calls for TransIP """ def __init__(self, *args, **kwargs): super(DomainService, self).__init__('DomainService', *args, **kwargs) def batch_check_availability(self, domain_names): """ Transip_DomainService::batchCheckAvailability Allows only 20 domain names per request :type domain_names: list of str :rtype: list of transip.service.objects.DomainCheckResult """ if len(domain_names) > 20: raise ValueError('There is a maximum of 20 domain names per request.') return self._simple_request('batchCheckAvailability', domain_names) def check_availability(self, domain_name): """ Transip_DomainService::checkAvailability :type domain_name: str :rtype: str the availability status of the domain name """ return self._simple_request('checkAvailability', domain_name) def get_whois(self, domain_name): """ Transip_DomainService::getWhois :type domain_name: str :rtype: str """ return self._simple_request('getWhois', domain_name) def get_domain_names(self): """ Transip_DomainService::getDomainNames :rtype: list of str """ return self._simple_request('getDomainNames') def get_info(self, domain_name): """ Retrieves information about the requested domain-name. :param domain_name: str :rtype: transip.service.objects.Domain """ cookie = self.build_cookie(mode=MODE_RO, method='getInfo', parameters=[domain_name]) self.update_cookie(cookie) # Perform the call result = self.soap_client.service.getInfo(domain_name) # Parse the result to well-known objects new_dns_entries = [] for dnsentry in result.dnsEntries: if dnsentry.__class__.__name__ == 'DnsEntry': new_dns_entries.append(DnsEntry(dnsentry.name, dnsentry.expire, dnsentry.type, dnsentry.content)) result.dnsEntries = new_dns_entries return result def batch_get_info(self, domain_names): """ Transip_DomainService::batchGetInfo :type domain_names: list of str :rtype: list of transip.service.objects.Domain """ return self._simple_request('batchGetInfo', domain_names) def get_auth_code(self, domain_name): """ Transip_DomainService::getAuthCode :type domain_name: str :rtype: str """ return self._simple_request('getAuthCode', domain_name) def get_is_locked(self, domain_name): """ Transip_DomainService::getIsLocked (@deprecated use getInfo) :type domain_name: str :rtype: bool """ return self._simple_request('getIsLocked', domain_name) def register(self, domain): """ Transip_DomainService::register :type domain: transip.service.object.Domain """ return self._simple_request('register', domain, mode=MODE_RW) def cancel(self, domain_name, end_time): """ Transip_DomainService::batchGetInfo :type domain_name: str :type end_time: datetime.datetime """ return self._simple_request('cancel', domain_name, end_time, mode=MODE_RW) def transfer_with_owner_change(self, domain, auth_code): """ Transip_DomainService::transferWithOwnerChange :type domain: transip.service.objects.Domain :type auth_code: str """ return self._simple_request('transferWithOwnerChange', domain, auth_code, mode=MODE_RW) def transfer_without_owner_change(self, domain, auth_code): """ Transip_DomainService::transferWithoutOwnerChange :type domain: transip.service.objects.Domain :type auth_code: str """ return self._simple_request('transferWithoutOwnerChange', domain, auth_code, mode=MODE_RW) def set_nameservers(self, domain_name, nameservers): """ Transip_DomainService::batchGetInfo :type domain_name: str :type nameservers: list of transip.service.objects.Nameserver """ return self._simple_request('setNameservers', domain_name, nameservers, mode=MODE_RW) def set_lock(self, domain_name): """ Transip_DomainService::batchGetInfo :type domain_name: str """ return self._simple_request('setLock', domain_name, mode=MODE_RW) def unset_lock(self, domain_name): """ Transip_DomainService::batchGetInfo """ return self._simple_request('unsetLock', domain_name, mode=MODE_RW) def set_dns_entries(self, domain_name, dns_entries): """ Sets the DnEntries for this Domain, will replace ALL existing dns entries with the new entries :type domain_name: str :type dns_entries: list of transip.service.objects.DnsEntry """ return self._simple_request('setDnsEntries', domain_name, dns_entries, mode=MODE_RW) def set_owner(self, domain_name, registrant_whois_contact): """ Transip_DomainService::batchGetInfo :type domain_name: str :type registrant_whois_contact: transip.service.objects.WhoisContact """ return self._simple_request('setOwner', domain_name, registrant_whois_contact, mode=MODE_RW) def set_contacts(self, domain_name, contacts): """ Transip_DomainService::setContacts :type domain_name: str :type contacts: list of transip.service.objects.WhoisContact """ return self._simple_request('setContacts', domain_name, contacts, mode=MODE_RW) def get_all_tld_infos(self): """ Transip_DomainService::batchGetInfo :rtype: list of transip.service.objects.Tld """ return self._simple_request('getAllTldInfos') def get_tld_info(self, tld_name): """ Transip_DomainService::getTldInfo :type tld_name: str :rtype: transip.service.objects.Tld """ return self._simple_request('getTldInfo', tld_name) def get_current_domain_action(self, domain_name): """ Transip_DomainService::getCurrentDomainAction :type domain_name: str :rtype: transip.service.objects.DomainAction """ return self._simple_request('getCurrentDomainAction', domain_name) def retry_current_domain_action_with_new_data(self, domain): # pylint: disable=invalid-name,locally-disabled """ Transip_DomainService::retryCurrentDomainActionWithNewData :type domain: transip.service.objects.Domain """ return self._simple_request('retryCurrentDomainActionWithNewData', domain) def retry_transfer_with_different_auth_code(self, domain, new_auth_code): # pylint: disable=invalid-name,locally-disabled """ Transip_DomainService::retryTransferWithDifferentAuthCode :param domain: transip.service.objects.Domain :type new_auth_code: str """ return self._simple_request('retryTransferWithDifferentAuthCode', domain, new_auth_code) def cancel_domain_action(self, domain): """ Transip_DomainService::cancelDomainAction :type domain: transip.service.objects.Domain """ return self._simple_request('cancelDomainAction', domain) transip-api-2.0.0/transip/service/haip.py000066400000000000000000000021751344345634200203700ustar00rootroot00000000000000# pylint: disable=too-many-public-methods """ The connector to HA-IP related API calls """ from transip.client import Client, MODE_RO, MODE_RW class HaipService(Client): """ Representation of the HaipService API calls for TransIP """ def __init__(self, *args, **kwargs): super(HaipService, self).__init__('HaipService', *args, **kwargs) def get_haip(self, haip_name): """ Get a HA-IP by name """ cookie = self.build_cookie(mode=MODE_RO, method='getHaip', parameters=[haip_name]) self.update_cookie(cookie) return self.soap_client.service.getHaip(haip_name) def get_haips(self): """ Get all HA-IPs """ cookie = self.build_cookie(mode=MODE_RO, method='getHaips') self.update_cookie(cookie) return self.soap_client.service.getHaips() def change_haip_vps(self, haip_name, vps_name): """ Changes the VPS connected to the HA-IP """ cookie = self.build_cookie(mode=MODE_RW, method='changeHaipVps', parameters=[haip_name, vps_name]) self.update_cookie(cookie) return self.soap_client.service.changeHaipVps(haip_name, vps_name) transip-api-2.0.0/transip/service/objects.py000066400000000000000000000172061344345634200211010ustar00rootroot00000000000000# pylint: disable=too-few-public-methods,invalid-name,too-many-instance-attributes """ Representations of the objects accepted and returned by the Transip API """ from suds.sudsobject import Object as SudsObject class DnsEntry(SudsObject): """ Representation of a DNS record as expected by the API """ TYPE_A = 'A' TYPE_AAAA = 'AAAA' TYPE_CNAME = 'CNAME' TYPE_MX = 'MX' TYPE_NS = 'NS' TYPE_TXT = 'TXT' TYPE_SRV = 'SRV' name = None expire = 0 type = None content = None def __init__(self, name, expire, record_type, content): """ Constructs a new DnsEntry of the form www IN 86400 A 127.0.0.1 mail IN 86400 CNAME @ Note that the IN class is always mandatory for this Entry and this is implied. :param name: the name of this DnsEntry, e.g. www, mail or @ :param expire: the expiration period of the dns entry, in seconds. For example 86400 for a day :param record_type: the type of this entry, one of the TYPE_ constants in this class :param content: content of of the dns entry, for example '10 mail', '127.0.0.1' or 'www' :type name: basestring :type expire: int :type record_type: basestring :type content: basestring """ super(DnsEntry, self).__init__() # Assign the fields self.name = name self.expire = expire self.type = record_type self.content = content def __eq__(self, other): # other can be a list. This check ensures that other is a DnsEntry. if not hasattr(self, 'name') or not hasattr(self, 'type') or not hasattr(self, 'content'): return False # expire is intentionally not used for equality. return self.name == other.name and self.type == other.type and self.content == other.content class Domain(SudsObject): """ Transip_Domain """ def __init__(self, name): super(Domain, self).__init__() self.name = name self.nameservers = [] self.contacts = [] self.dnsEntries = [] self.branding = None self.authCode = '' self.isLocked = False self.registrationDate = '' self.renewalDate = '' class Nameserver(SudsObject): """ Transip_Nameserver """ def __init__(self, hostname, ipv4=None, ipv6=None): super(Nameserver, self).__init__() self.hostname = hostname self.ipv4 = ipv4 self.ipv6 = ipv6 class WhoisContract(SudsObject): """ Transip_WhoisContract """ def __init__(self): super(WhoisContract, self).__init__() self.type = '' self.firstName = '' self.middleName = '' self.lastName = '' self.companyName = '' self.companyKvk = '' self.companyType = '' self.street = '' self.number = '' self.postalCode = '' self.city = '' self.phoneNumber = '' self.faxNumber = '' self.email = '' self.country = '' class DomainBranding(SudsObject): """ Transip_DomainBranding """ def __init__(self): super(DomainBranding, self).__init__() self.companyName = '' self.supportEmail = '' self.companyUrl = '' self.termsOfUsageUrl = '' self.bannerLine1 = '' self.bannerLine2 = '' self.bannerLine3 = '' class WebhostingPackage(SudsObject): """ Transip_WebhostingPackage representation """ def __init__(self, name, description, price, renewalPrice): super(WebhostingPackage, self).__init__() self.name = name self.description = description self.price = price self.renewalPrice = renewalPrice class WebHost(SudsObject): """ Transip_WebHost representation """ def __init__(self, domainName): super(WebHost, self).__init__() self.domainName = domainName self.cronjobs = None self.mailBoxes = None self.dbs = None self.mailForwards = None self.subDomains = None class MailBox(SudsObject): """ Transip_MailBox representation """ SPAMCHECKER_STRENGTH_AVERAGE = 'AVERAGE' SPAMCHECKER_STRENGTH_OFF = 'OFF' SPAMCHECKER_STRENGTH_LOW = 'LOW' SPAMCHECKER_STRENGTH_HIGH = 'HIGH' def __init__(self, address, maxDiskUsage=20): super(MailBox, self).__init__() self.address = address self.spamCheckerStrength = MailBox.SPAMCHECKER_STRENGTH_AVERAGE self.maxDiskUsage = maxDiskUsage self.hasVacationReply = '' self.vacationReplySubject = '' self.vacationReplyMessage = '' def __eq__(self, other): if isinstance(other, MailBox): return self.address == other.address if hasattr(other, 'value'): return self.address == other.value.address return self.address == other class MailForward(SudsObject): """ Transip_MailForward representation """ def __init__(self, name, targetAddress): super(MailForward, self).__init__() self.name = name self.targetAddress = targetAddress def __eq__(self, other): if isinstance(other, MailForward): return self.targetAddress == other.targetAddress and self.name == other.name if hasattr(other, 'value'): return self.targetAddress == other.value.targetAddress and self.name == other.value.name return self.name == other class Tld(SudsObject): """ Transip_Tld representation """ CAPABILITY_REQUIRESAUTHCODE = 'requiresAuthCode' CAPABILITY_CANREGISTER = 'canRegister' CAPABILITY_CANTRANSFERWITHOWNERCHANGE = 'canTransferWithOwnerChange' CAPABILITY_CANTRANSFERWITHOUTOWNERCHANGE = 'canTransferWithoutOwnerChange' CAPABILITY_CANSETLOCK = 'canSetLock' CAPABILITY_CANSETOWNER = 'canSetOwner' CAPABILITY_CANSETCONTACTS = 'canSetContacts' CAPABILITY_CANSETNAMESERVERS = 'canSetNameservers' def __init__(self, name): super(Tld, self).__init__() self.name = name self.price = 0.0 self.renewalPrice = 0.0 self.capabilities = [] self.registrationPeriodLength = '' self.cancelTimeFrame = '' class DomainAction(SudsObject): """ Transip_DomainAction representation """ def __init__(self, name, hasFailed, message): super(DomainAction, self).__init__() self.name = name self.hasFailed = hasFailed self.message = message class WhoisContact(SudsObject): """ Transip_WhoisContact representation """ def __init__(self): super(WhoisContact, self).__init__() self.type = '' self.firstName = '' self.middleName = '' self.lastName = '' self.companyName = '' self.companyKvk = '' self.companyType = '' self.street = '' self.number = '' self.postalCode = '' self.city = '' self.phoneNumber = '' self.faxNumber = '' self.email = '' self.country = '' class DomainCheckResult(SudsObject): """ Transip_DomainCheckResult representation """ STATUS_INYOURACCOUNT = 'inyouraccount' STATUS_UNAVAILABLE = 'unavailable' STATUS_NOTFREE = 'notfree' STATUS_FREE = 'free' STATUS_INTERNALPULL = 'internalpull' STATUS_INTERNALPUSH = 'internalpush' ACTION_REGISTER = 'register' ACTION_TRANSFER = 'transfer' ACTION_INTERNALPULL = 'internalpull' def __init__(self, domainName, status, actions): super(DomainCheckResult, self).__init__() self.domainName = domainName self.status = status self.actions = actions transip-api-2.0.0/transip/service/vps.py000066400000000000000000000361111344345634200202540ustar00rootroot00000000000000# pylint: disable=too-many-public-methods """ The connector to VPS related API calls """ from transip.client import Client, MODE_RO, MODE_RW class VpsService(Client): """ Representation of the VpsService API calls for TransIP """ def __init__(self, *args, **kwargs): super(VpsService, self).__init__('VpsService', *args, **kwargs) def get_available_products(self): """ Get available VPS products """ cookie = self.build_cookie(mode=MODE_RO, method='getAvailableProducts') self.update_cookie(cookie) return self.soap_client.service.getAvailableProducts() def get_available_addons(self): """ Get available VPS addons """ cookie = self.build_cookie(mode=MODE_RO, method='getAvailableAddons') self.update_cookie(cookie) return self.soap_client.service.getAvailableAddons() def get_available_availability_zones(self): """ Get available availability zones """ # pylint: disable=invalid-name cookie = self.build_cookie(mode=MODE_RO, method='getAvailableAvailabilityZones') self.update_cookie(cookie) return self.soap_client.service.getAvailableAvailabilityZones() def get_active_addons_for_vps(self, vps_name): """ Get all the Active Addons for Vps """ cookie = self.build_cookie(mode=MODE_RO, method='getActiveAddonsForVps', parameters=[vps_name]) self.update_cookie(cookie) return self.soap_client.service.getActiveAddonsForVps(vps_name) def get_available_upgrades(self, vps_name): """ Get available VPS upgrades for a specific Vps """ cookie = self.build_cookie(mode=MODE_RO, method='getAvailableUpgrades', parameters=[vps_name]) self.update_cookie(cookie) return self.soap_client.service.getAvailableUpgrades(vps_name) def get_available_addons_for_vps(self, vps_name): """ Get available Addons for Vps """ cookie = self.build_cookie(mode=MODE_RO, method='getAvailableAddonsForVps', parameters=[vps_name]) self.update_cookie(cookie) return self.soap_client.service.getAvailableAddonsForVps(vps_name) def get_cancellable_addons_for_vps(self, vps_name): """ Get cancellable addons for specific Vps """ cookie = self.build_cookie(mode=MODE_RO, method='getCancellableAddonsForVps', parameters=[vps_name]) self.update_cookie(cookie) return self.soap_client.service.getCancellableAddonsForVps(vps_name) def order_vps(self, product_name, addons, operating_system_name, hostname): """ Order a VPS with optional Addons """ if not addons: # An empty list of Addons gives a signature error due to the Addons # not being added to the OrderedDict in # transip.client.Client._build_signature_message. addons = None else: # A list of Addons (or an empty list) gives a signature error due # to the Addons not being added to the OrderedDict in # transip.client.Client._build_signature_message. # The _build_signature_message method only adds list items if # they are an instance of SudsObject. raise NotImplementedError('Addons paramenter not implemented. Use ' 'the order_addon method instead.') cookie = self.build_cookie(mode=MODE_RW, method='orderVps', \ parameters=[product_name, addons, operating_system_name, hostname]) self.update_cookie(cookie) return self.soap_client.service.orderVps(product_name, addons, operating_system_name, hostname) def order_vps_in_availability_zone(self, product_name, addons, operating_system_name, hostname, availability_zone): """ Order a VPS with optional Addons in a availability zone """ if not addons: # An empty list of Addons gives a signature error due to the Addons # not being added to the OrderedDict in # transip.client.Client._build_signature_message. addons = None else: # A list of Addons (or an empty list) gives a signature error due # to the Addons not being added to the OrderedDict in # transip.client.Client._build_signature_message. # The _build_signature_message method only adds list items if # they are an instance of SudsObject. raise NotImplementedError('Addons paramenter not implemented. Use ' 'the order_addon method instead.') cookie = self.build_cookie(mode=MODE_RW, method='orderVpsInAvailabilityZone', \ parameters=[product_name, addons, operating_system_name, hostname, availability_zone]) self.update_cookie(cookie) return self.soap_client.service.orderVpsInAvailabilityZone(product_name, addons, \ operating_system_name, hostname, availability_zone) def clone_vps(self, vps_name): """ Clone a VPS """ cookie = self.build_cookie(mode=MODE_RW, method='cloneVps', parameters=[vps_name]) self.update_cookie(cookie) return self.soap_client.service.cloneVps(vps_name) def clone_vps_to_availability_zone(self, vps_name, availability_zone): """ Clone a VPS to a availability zone """ cookie = self.build_cookie(mode=MODE_RW, method='cloneVpsToAvailabilityZone', \ parameters=[vps_name, availability_zone]) self.update_cookie(cookie) return self.soap_client.service.cloneVpsToAvailabilityZone(vps_name, availability_zone) def order_addon(self, vps_name, addons): """ Order addons to a VPS """ cookie = self.build_cookie(mode=MODE_RW, method='orderAddon', parameters=[vps_name, addons]) self.update_cookie(cookie) return self.soap_client.service.orderAddon(vps_name, addons) def order_private_network(self): """ Order a private Network """ cookie = self.build_cookie(mode=MODE_RW, method='orderPrivateNetwork') self.update_cookie(cookie) return self.soap_client.service.orderPrivateNetwork() def upgrade_vps(self, vps_name, upgrade_name): """ upgrade a Vps """ cookie = self.build_cookie(mode=MODE_RW, method='upgradeVps', parameters=[vps_name, upgrade_name]) self.update_cookie(cookie) return self.soap_client.service.upgradeVps(vps_name, upgrade_name) def cancel_vps(self, vps_name, end_time): """ Cancel a Vps """ cookie = self.build_cookie(mode=MODE_RW, method='cancelVps', parameters=[vps_name, end_time]) self.update_cookie(cookie) return self.soap_client.service.cancelVps(vps_name, end_time) def cancel_addon(self, vps_name, addon_name): """ Cancel a Vps Addon """ cookie = self.build_cookie(mode=MODE_RW, method='cancelAddon', parameters=[vps_name, addon_name]) self.update_cookie(cookie) return self.soap_client.service.cancelAddon(vps_name, addon_name) def cancel_private_network(self, private_network_name, end_time): """ Cancel a PrivateNetwork """ cookie = self.build_cookie(mode=MODE_RW, method='cancelPrivateNetwork', \ parameters=[private_network_name, end_time]) self.update_cookie(cookie) return self.soap_client.service.cancelPrivateNetwork(private_network_name, end_time) def get_private_networks_by_vps(self, vps_name): """ Get Private networks for a specific vps """ cookie = self.build_cookie(mode=MODE_RO, method='getPrivateNetworksByVps', parameters=[vps_name]) self.update_cookie(cookie) return self.soap_client.service.getPrivateNetworksByVps(vps_name) def get_all_private_networks(self): """ Get all Private networks in your account """ cookie = self.build_cookie(mode=MODE_RO, method='getAllPrivateNetworks') self.update_cookie(cookie) return self.soap_client.service.getAllPrivateNetworks() def add_vps_to_private_network(self, vps_name, private_network_name): """ Add VPS to a private Network """ cookie = self.build_cookie(mode=MODE_RW, method='addVpsToPrivateNetwork', \ parameters=[vps_name, private_network_name]) self.update_cookie(cookie) return self.soap_client.service.addVpsToPrivateNetwork(vps_name, private_network_name) def remove_vps_from_private_network(self, vps_name, private_network_name): """ Remove VPS from a private Network """ cookie = self.build_cookie(mode=MODE_RW, method='removeVpsFromPrivateNetwork', \ parameters=[vps_name, private_network_name]) self.update_cookie(cookie) return self.soap_client.service.removeVpsFromPrivateNetwork(vps_name, private_network_name) # This function gives a type not found exception # def get_traffic_information_for_vps(self, vps_name): # """ Get Traffic information by vps_name for this contractPeriod """ # cookie = self.build_cookie(mode=MODE_RO, method='getTrafficInformationForVps', parameters=[vps_name]) # self.update_cookie(cookie) # return self.soap_client.service.getTrafficInformationForVps(vps_name) def start(self, vps_name): """ Start a Vps """ cookie = self.build_cookie(mode=MODE_RW, method='start', parameters=[vps_name]) self.update_cookie(cookie) return self.soap_client.service.start(vps_name) def stop(self, vps_name): """ Stop a Vps """ cookie = self.build_cookie(mode=MODE_RW, method='stop', parameters=[vps_name]) self.update_cookie(cookie) return self.soap_client.service.stop(vps_name) def reset(self, vps_name): """ Reset a Vps """ cookie = self.build_cookie(mode=MODE_RW, method='reset', parameters=[vps_name]) self.update_cookie(cookie) return self.soap_client.service.reset(vps_name) def create_snapshot(self, vps_name, description): """ Create a snapshot """ cookie = self.build_cookie(mode=MODE_RW, method='createSnapshot', parameters=[vps_name, description]) self.update_cookie(cookie) return self.soap_client.service.createSnapshot(vps_name, description) def revert_snapshot(self, vps_name, snapshot_name): """ Revert a snapshot """ cookie = self.build_cookie(mode=MODE_RW, method='revertSnapshot', parameters=[vps_name, snapshot_name]) self.update_cookie(cookie) return self.soap_client.service.revertSnapshot(vps_name, snapshot_name) def revert_snapshot_to_other_vps(self, sourcevps_name, snapshot_name, destinationvps_name): """ Revert a snapshot to another VPS """ cookie = self.build_cookie(mode=MODE_RW, method='revertSnapshotToOtherVps',\ parameters=[sourcevps_name, snapshot_name, destinationvps_name]) self.update_cookie(cookie) return self.soap_client.service.revertSnapshotToOtherVps(sourcevps_name, snapshot_name, destinationvps_name) def remove_snapshot(self, vps_name, snapshot_name): """ Remove a snapshot """ cookie = self.build_cookie(mode=MODE_RW, method='removeSnapshot', parameters=[vps_name, snapshot_name]) self.update_cookie(cookie) return self.soap_client.service.removeSnapshot(vps_name, snapshot_name) def revert_vps_backup(self, vps_name, backup_id): """ Revert a vps backup """ cookie = self.build_cookie(mode=MODE_RW, method='revertVpsBackup', parameters=[vps_name, backup_id]) self.update_cookie(cookie) return self.soap_client.service.revertVpsBackup(vps_name, backup_id) def get_vps(self, vps_name): """ Get a Vps by name """ cookie = self.build_cookie(mode=MODE_RO, method='getVps', parameters=[vps_name]) self.update_cookie(cookie) return self.soap_client.service.getVps(vps_name) def get_vpses(self): """ Get all Vpses """ cookie = self.build_cookie(mode=MODE_RO, method='getVpses') self.update_cookie(cookie) return self.soap_client.service.getVpses() def get_snapshots_by_vps(self, vps_name): """ Get all Snapshots for a vps """ cookie = self.build_cookie(mode=MODE_RO, method='getSnapshotsByVps', parameters=[vps_name]) self.update_cookie(cookie) return self.soap_client.service.getSnapshotsByVps(vps_name) def get_vps_backups_by_vps(self, vps_name): """ Get all VpsBackups for a vps """ cookie = self.build_cookie(mode=MODE_RO, method='getVpsBackupsByVps', parameters=[vps_name]) self.update_cookie(cookie) return self.soap_client.service.getVpsBackupsByVps(vps_name) def get_operating_systems(self): """ Get all operating systems """ cookie = self.build_cookie(mode=MODE_RO, method='getOperatingSystems') self.update_cookie(cookie) return self.soap_client.service.getOperatingSystems() def install_operating_system(self, vps_name, operating_system_name, hostname): """ Install an operating system on a vps """ cookie = self.build_cookie(mode=MODE_RW, method='installOperatingSystem', \ parameters=[vps_name, operating_system_name, hostname]) self.update_cookie(cookie) return self.soap_client.service.installOperatingSystem(vps_name, operating_system_name, hostname) def install_unattended(self, vps_name, operating_system_name, base64_install_text): """ Install an operating system on a vps with a unattended installfile """ cookie = self.build_cookie(mode=MODE_RW, method='installOperatingSystemUnattended', \ parameters=[vps_name, operating_system_name, base64_install_text]) self.update_cookie(cookie) return self.soap_client.service.installOperatingSystemUnattended(vps_name, \ operating_system_name, base64_install_text) def get_ips_for_vps(self, vps_name): """ Get Ips for a specific Vps """ cookie = self.build_cookie(mode=MODE_RW, method='getIpsForVps', parameters=[vps_name]) self.update_cookie(cookie) return self.soap_client.service.getIpsForVps(vps_name) def get_all_ips(self): """ Get All ips """ cookie = self.build_cookie(mode=MODE_RO, method='getAllIps') self.update_cookie(cookie) return self.soap_client.service.getAllIps() def add_ipv6_to_vps(self, vps_name, ipv6_address): """ Add Ipv6 Address to Vps """ cookie = self.build_cookie(mode=MODE_RW, method='addIpv6ToVps', parameters=[vps_name, ipv6_address]) self.update_cookie(cookie) return self.soap_client.service.addIpv6ToVps(vps_name, ipv6_address) def set_customer_lock(self, vps_name, enabled): """ Enable or Disable a Customer Lock for a Vps """ enabled = int(enabled) cookie = self.build_cookie(mode=MODE_RW, method='setCustomerLock', parameters=[vps_name, enabled]) self.update_cookie(cookie) return self.soap_client.service.setCustomerLock(vps_name, enabled) def handover_vps(self, vps_name, target_accountname): """ Handover a VPS to another TransIP User """ cookie = self.build_cookie(mode=MODE_RW, method='handoverVps', parameters=[vps_name, target_accountname]) self.update_cookie(cookie) return self.soap_client.service.handoverVps(vps_name, target_accountname) transip-api-2.0.0/transip/service/webhosting.py000066400000000000000000000050641344345634200216200ustar00rootroot00000000000000""" Implementation of the WebhostingService API endpoint """ from transip.client import Client, MODE_RW class WebhostingService(Client): """ Transip_WebhostingService """ def __init__(self, *args, **kwargs): """ Constructor """ super(WebhostingService, self).__init__('WebhostingService', *args, **kwargs) def get_webhosting_domain_names(self): """ Transip_WebhostingService::getWebhostingDomainNames """ return self._simple_request('getWebhostingDomainNames') def get_available_packages(self): """ Transip_WebhostingService::getAvailablePackages """ return self._simple_request('getAvailablePackages') def get_info(self, domain): """ Transip_WebhostingService::getInfo """ return self._simple_request('getInfo', domain) def get_available_upgrades(self, domain): """ Transip_WebhostingService::getAvailableUpgrades """ return self._simple_request('getAvailableUpgrades', domain) def create_mailbox(self, domain, mailbox): """ Transip_WebhostingService::createMailBox """ return self._simple_request('createMailBox', domain, mailbox, mode=MODE_RW) def set_mailbox_password(self, domain, mailbox, password): """ Transip_WebhostingService::setMailBoxPassword """ return self._simple_request('setMailBoxPassword', domain, mailbox, password, mode=MODE_RW) def update_mailbox(self, domain, mailbox): """ Transip_WebhostingService::modifyMailBox """ return self._simple_request('modifyMailBox', domain, mailbox, mode=MODE_RW) def delete_mailbox(self, domain, mailbox): """ Transip_WebhostingService::deleteMailBox """ return self._simple_request('deleteMailBox', domain, mailbox, mode=MODE_RW) def create_mail_forward(self, domain, mailforward): """ Transip_WebhostingService::createMailForward """ return self._simple_request('createMailForward', domain, mailforward, mode=MODE_RW) def update_mail_forward(self, domain, mailforward): """ Transip_WebhostingService::modifyMailForward """ return self._simple_request('modifyMailForward', domain, mailforward, mode=MODE_RW) def delete_mail_forward(self, domain, mailforward): """ Transip_WebhostingService::deleteMailForward """ return self._simple_request('deleteMailForward', domain, mailforward, mode=MODE_RW) transip-api-2.0.0/transip/transip_cli.py000066400000000000000000000112041344345634200203070ustar00rootroot00000000000000""" The CLI parser for the API """ from __future__ import print_function import argparse import logging from suds import WebFault from transip.service.domain import DomainService from transip.service.objects import DnsEntry logging.basicConfig(level=logging.INFO) logging.getLogger('suds.client').setLevel(logging.INFO) def show_dns_entries(domain_service, domain_name): """ Lists all DNS entries for the provided domain name :param domain_service: an initialized DomainService object :param domain_name: domain name :return: """ try: dns_entries = domain_service.get_info(domain_name).dnsEntries except WebFault as err: print(err) exit(1) print(dns_entries) def update_dns(domain_service, args): """ Adds, updates or deletes a DNS entry through the API :param domain_service: an initialized DomainService object :param args: arguments object from argparse """ try: dns_entries = domain_service.get_info(args.domain_name).dnsEntries except WebFault as err: print(err) exit(1) number_of_entries = len(dns_entries) for entry in dns_entries: if args.add_dns_entry and entry.name == args.entry_name and entry.type == args.entry_type and \ entry.content == args.entry_content: print('The DNS entry already exists.') exit(1) elif args.update_dns_entry and entry.name == args.entry_name and entry.type == args.entry_type: dns_entries.remove(entry) elif args.delete_dns_entry and entry.name == args.entry_name and entry.type == args.entry_type and \ entry.expire == args.entry_expire and entry.content == args.entry_content: dns_entries.remove(entry) if args.update_dns_entry or args.delete_dns_entry: if number_of_entries == len(dns_entries): print('The DNS entry was not found.') exit(1) if args.add_dns_entry or args.update_dns_entry: dns_entries.append(DnsEntry(args.entry_name, args.entry_expire, args.entry_type, args.entry_content)) try: result = domain_service.set_dns_entries(args.domain_name, dns_entries) except WebFault as err: print(err) exit(1) if result is None: print('Request finished successfully.') else: print(result) def main(): """ The main method """ parser = argparse.ArgumentParser() parser.add_argument('-l', '--login-name', help='TransIP username', dest='loginname') parser.add_argument('-s', '--show-dns-entries', help='show all DNS entries for a domain', action='store_true') parser.add_argument('-a', '--add-dns-entry', help='add an entry in the DNS', action='store_true') parser.add_argument('-u', '--update-dns-entry', help='update an entry in the DNS', action='store_true') parser.add_argument('-d', '--delete-dns-entry', help='delete an entry in the DNS', action='store_true') parser.add_argument('--domain-name', help='domain name to use', dest='domain_name') parser.add_argument('--entry-name', help='name of the DNS entry', dest='entry_name') parser.add_argument('--entry-expire', help='expire time of the DNS entry', dest='entry_expire', type=int) parser.add_argument('--entry-type', help='type of the DNS entry', dest='entry_type') parser.add_argument('--entry-content', help='content of the DNS entry', dest='entry_content') parser.add_argument('--api-key', help='TransIP private key', dest='api_key_file') args = parser.parse_args() if not args.loginname: print('Please provide your TransIP username.') exit(1) if not args.api_key_file: args.api_key_file = 'decrypted_key' domain_service = DomainService(args.loginname, args.api_key_file) if args.add_dns_entry or args.update_dns_entry or args.delete_dns_entry: if [args.add_dns_entry, args.update_dns_entry, args.delete_dns_entry].count(True) > 1: print('Please use only one of the options: ' '-a/--add-dns-entry, -u/--update-dns-entry, -d/--delete-dns-entry') exit(1) if args.domain_name and args.entry_name and args.entry_expire and args.entry_type and args.entry_content: update_dns(domain_service, args) else: print('Please provide the details of the DNS entry.') exit(1) elif args.show_dns_entries: if args.domain_name: show_dns_entries(domain_service, args.domain_name) else: print('Please provide the domain name.') exit(1) else: names = domain_service.get_domain_names() print(names) if __name__ == '__main__': main()