diff --git a/docs/advanced.rst b/docs/advanced.rst index ee29f2e..2acdd08 100644 --- a/docs/advanced.rst +++ b/docs/advanced.rst @@ -2,37 +2,31 @@ Advanced Topics =============== -This Section serves as a collective for advanced topics that most developers -using this library will never need to know about, but that may be useful for -developers who are destined to maintain this package +This section is a collection of advanced topics for users who intend to contribute +and maintain this library. Sessions -------- -The way in which sessions are handled in this library are designed to be super -easy to use for developers who use this library, however, have become relatively -complex internally. Due to their ease of use to the front end user these docs are -mainly for developers who would like to contribute to this code base, or who are -just curious as to what is actually going on under the hood. +Sessions in this library are designed for ease of use by front-end users. +However, this section is dedicated to a deeper understanding of Sessions for +advanced users and contributors to this library. Parent Class ^^^^^^^^^^^^ Both :class:`dyn.tm.session.DynectSession` and :class:`dyn.mm.session.MMSession` are subclasses of :class:`dyn.core.SessionEngine`. The :class:`dyn.core.SessionEngine` -provides an easy to use internal API for preparing, sending, and processing outbound -API calls. This class was added in v1.0.0 and greatly reduced the amount of logic -and duplicated code that made looking at these sessions so overly complex. +provides a simple internal API for preparing, sending, and processing outbound +API calls. This class was added in v1.0.0 and reduced the amount of logic +and duplicated code that made understanding these Sessions difficult. Parent Type ^^^^^^^^^^^ -Since v0.4.0 sessions had always been implemented as a Singleton type. At this point -you're probably asing "Why?" And that's a bit of a complicated question. One of the main -reasons that these sessions were implemented as a Singleton was to make it easier for -the end user to use this SDK and to make the flow of logic in trying to utilize the -API much smoother. By implementing Sessions as a singleton internally, it allows the -user to not need to hang on to their session objects (unless they want to). It also -means that users don't need to pass their session information around to all of the other -classes in this library in order to make API calls. (ie):: +Since v0.4.0, Sessions have been implemented as a Singleton type. This made it easier +for end users to use the SDK and to utilize the API. By internally implementing Sessions +as a Singleton, it allows the user discard their Session objects, unless they wish to +keep them. It also doesn’t require users to share their Session information with +other classes in this library to make API calls. (EXAMPLE):: >>> from dyn.tm.session import DynectSession >>> from dyn.tm.zones import get_all_zones @@ -40,30 +34,28 @@ classes in this library in order to make API calls. (ie):: >>> zones = get_all_zones() -as opposed to something along these lines:: +as opposed to something like this:: >>> from dyn.tm.session import DynectSession >>> from dyn.tm.zones import get_all_zones >>> my_session = DynectSession(**my_credentials) >>> zones = get_all_zones(my_session) -Or, in my opinion, even worse:: +Or, even worse:: >>> from dyn.tm.session import DynectSession >>> my_session = DynectSession(**my_credentials) >>> zones = my_session.get_all_zones(my_session) -In these basic examples it may not seem like this is a terribly huge deal, but when -you're dealing with creating multiple types of records, or adding/editing a Traffic -Director service or other complex service, not needing to pass your session around -to the correct places, or use it as a point of entry to other functionality is a huge -relief. +In these examples, the changes may not seem significant but gain more relevance when +creating multiple types of records, adding or editing Traffic Director and other complex +services. Not needing to share your Session with other classes, or use it as a point +of entry to other functionality, makes using this SDK much simpler. What We Used to Do ^^^^^^^^^^^^^^^^^^ -Now that we've gone over the Singleton implementation from a front end POV, let's -talk about it from a backend POV. Effectively what we used to do in each of the Session -types was this:: +From a backend perspective, the following is an example of how Session types were +handled before v0.4.0:: def session(): """Accessor for the current Singleton DynectSession""" @@ -89,19 +81,17 @@ types was this:: globals()['SESSION'] = super(DynectSession, cls).__new__(cls, *args) return globals()['SESSION'] -It was a dirty hack that worked for a while, but, it had several fatal flaws. - 1. Once we added Message Management support we needed to duplicate this code to rename the 'SESSION' key to 'MM_SESSION', which is less than ideal due to code duplication - 2. This allowed you to only have one active session, even in shared memory space (ie threads) - 3. Due to the not-so-global scope of globals, this session was really only "global" in the scope of the dyn.tm module. It could still be accessed externally, but it just made me feel dirty knowing that that was what was happening. +While this worked for a short while, it had its flaws: + 1. Once Message Management support was added, the code needed to be duplicated to rename the ‘SESSION’ key to ‘MM_SESSION’. This was inefficient. + 2. This allowed you to only have one active Session, even in shared memory space, i.e. threads. + 3. Sessions were only truly “global” in the scope of the dyn.tm module. It could still be accessed externally, but it was less than ideal. What We Do Now ^^^^^^^^^^^^^^ -So, as of v1.0.0 this is not how the Session types are implemented anymore. Yes, they -are still Singletons, however, they're implemented completely differently. +As of v1.0.0, Session types remain Singletons but are implemented differently. -Now, on top of these Sessions being implemented as :class:`dyn.core.SessionEngine` -objects, they are also :class:`dyn.core.Singleton` *type* objects. What do these -look like you ask?:: +Sessions are now implemented as :class:`dyn.core.SessionEngine` objects +and :class:`dyn.core.Singleton` *type* objects. EXAMPLE:: class Singleton(type): """A :class:`Singleton` type for implementing a true Singleton design @@ -119,44 +109,40 @@ look like you ask?:: } return cls._instances[key][cur_thread] -So, the Singleton type is applied as a *__metaclass__* in each of the two Session -types. This allows for a much cleaner implementation of Singletons where every time -one is accessed it will globally (actually globally this time) have knowledge of -other instances, since those instances are tied to the classes themselves instead -of held in the *globals* of the session modules. In addition this allows users -to have multiple active sessions across multiple threads, which was previously -impossible in the prior implementation. +The Singleton type is applied as a *__metaclass__* in each of the two Session +types. This allows for a much cleaner implementation of Singletons. Every time +one is accessed, it will globally have knowledge of other instances, as those +instances are tied to the classes themselves instead of held in the *globals* +of the session modules. In addition, this allows users to have multiple active +sessions across multiple threads, which was not possible in the prior +implementation. Password Encryption ------------------- -The DynECT REST API only accepts passwords in plain text, and currently there is -no way around that. However, for those of you that are particularly mindful of -security (and even those of you who aren't) can probably see some serious pitfalls -to this. As far as most users of this library are concerned the passwords stored in -their :class:`~dyn.tm.session.DynectSession` objects will only ever live in memory, -so it's really not a huge deal that their passwords are stored in plain text. However, -for users looking to do more advanced things, such as serialize and store their session -objects in something less secure, such as a database, then these plain text passwords -are far less than ideal. Because of this in version 1.1.0 we've added optional -AES-256 password encryption for all :class:`~dyn.tm.session.DynectSession` -instances. All you need to do to enable password encryption is install -`PyCrypto `_. The rest will happen -automatically. +The Managed DNS REST API only accepts passwords in plain text. The +passwords stored in :class:`~dyn.tm.session.DynectSession` objects only +live in memory, reducing the security risk of plain text passwords in this instance. +However, for users looking to do more advanced things, such as serialize and store +their session objects in something less secure, such as a database, these +plain text passwords are not ideal. In response to this, Dyn added optional AES-256 +password encryption for all :class:`~dyn.tm.session.DynectSession` instances in +version 1.1.0. To enable password encryption, install +`PyCrypto `_. Key Generation ^^^^^^^^^^^^^^ -Also in version 1.1.0 an optional key field parameter was added to the +In version 1.1.0, an optional key field parameter was added to the :class:`~dyn.tm.session.DynectSession` __init__ method. This field will allow -you to specify the key that your password will be encrypted using. However, -you may also choose to let the dyn module handle the key generation for you as -well using the :func:`~dyn.encrypt.generate_key` function which generates a, -nearly, random 50 character key that can be easily consumed by the -:class:`~dyn.encrypt.AESCipher` class (the class responsible for performing -the actual encryption and decryption. +you to specify the key that your encrypted password will be using. You can also +let the Dyn module handle the key generation in addition to using +the :func:`~dyn.encrypt.generate_key` function, which generates a random +50 character key that can be easily consumed by the :class:`~dyn.encrypt.AESCipher` +class (the class responsible for performing the encryption and decryption). Encrypt Module ^^^^^^^^^^^^^^ +:: .. autofunction:: dyn.encrypt.generate_key .. autoclass:: dyn.encrypt.AESCipher diff --git a/docs/core.rst b/docs/core.rst index 7c251e5..38be044 100644 --- a/docs/core.rst +++ b/docs/core.rst @@ -3,7 +3,7 @@ Core ==== The :mod:`dyn.core` module contains functionality that is core to the behavior -of the rest of the library. In particular this is where a lot of the "heavy lifting" +of the rest of the library. This is where a lot of the "heavy lifting" for sessions is done. diff --git a/docs/install.rst b/docs/install.rst index 77ff712..d5dd7c3 100644 --- a/docs/install.rst +++ b/docs/install.rst @@ -3,24 +3,27 @@ Installation ============ -This part of the documentation covers the installation of the dyn module. -The first step to using any software package is getting it properly installed. +This part of the documentation covers the installation of the Dyn module. Distribute & Pip ---------------- -Installing dyn is simple via `pip `_. +The easiest way to install the Dyn module is via ‘pip’. + +1. Go to ’, download and install ‘pip’. +2. In Terminal, run: $ pip install dyn Get the Code ------------ -dyn is actively developed on GitHub, the code is -`always available `_. +Dyn is actively developed on GitHub, the code is always available +''` and there are several options +available to obtain the code. -You can either clone the public repository:: +Clone the public repository:: git clone https://github.com/dyninc/dyn-python.git @@ -28,7 +31,7 @@ Download the `tarball `_:: $ curl -OL https://github.com/dyninc/dyn-python/tarball/master -Or, download the `zipball `_:: +Download the `zipball `_:: $ curl -OL https://github.com/dyninc/dyn-python/zipball/master @@ -36,4 +39,3 @@ Once you have a copy of the source, you can embed it in your Python package, or install it into your site-packages by running:: $ python setup.py install -