-
Notifications
You must be signed in to change notification settings - Fork 27
Fixes #401 Networking capabilities should be documented #402
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
23e133e
411617d
6bd9e03
c8be125
f641967
e5b290f
3cf4c96
97fda46
9366228
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| # Plugin Runtime Environment | ||
|
|
||
| ## Process Lifetime | ||
| Plugin code runs inside of a Python interpreter process on the Delphix Engine. | ||
|
|
||
| A fair question to ask is "What is the lifetime of this interpreter process?" After all, if the interpreter | ||
| process runs for a long time, then the plugin might be able to store things in memory for later access. | ||
|
|
||
| Unfortunately, **there are no guarantees about process lifetime**. Your interpreter process could last two years, or it could last 400 microseconds. There is no way to know or predict this ahead of time. | ||
|
|
||
| So, do not make any assumptions about interpreter process lifetime in your plugin code. | ||
|
|
||
|
|
||
| ## Available Modules | ||
| Our Python 2.7 runtime environment only contains the [Python Standard Library](https://docs.python.org/2/library/). No additional Python modules/libraries are available. | ||
|
|
||
| If you want to use some Python module that is not part of the standard library, you might be able to do so. | ||
| You would need to include that library as part of your plugin. That would involve downloading the source | ||
| code for that module, and copying it into your source directory. For more information on how to lay out code in your source directory, see [Code Sharing](/Best_Practices/Code_Sharing.md). | ||
|
|
||
| ### Warnings | ||
| There are two major things to watch out for if you decide to incorporate a 3rd-party library. | ||
|
|
||
| 1) Make sure you're legally allowed to do so! The licensing agreement on the module will decide if, and | ||
| under what circumstances, you're allowed to make copies of, and redistribute the module. Some modules will | ||
| allow this, some will disallow this, and some will allow this for a fee. | ||
|
|
||
| 2) Some Python libraries include native code (often written in C or C++). There is no support for using | ||
| such libraries with plugin code. The reason for this is that native code needs to be | ||
| specially compiled and built for the machine that it the library will be running on. And, unfortunately, | ||
| the machine your plugin runs on (the Delphix Engine) is likely very different from the machine you use | ||
| to develop and build your plugin. | ||
|
Comment on lines
+21
to
+32
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should we move this to the code sharing best practices section?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Today, the "code sharing" section really doesn't talk about 3rd-party code at all. It's focused on how plugin code can be broken up into separate modules. So, my thinking here was...
I do think that at least a link from code sharing back to this section would be good, though. I can add that.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added the link. Let me know if you think the rest is okay. |
||
|
|
||
| ## Network Access | ||
| As of Delphix Engine version 6.0.11.0, plugin code is able to use the network directly. No network access is | ||
| possible in earlier versions. | ||
|
|
||
| For example, suppose your plugin wants to talk to some DBMS running on some remote host. | ||
| If the DBMS supports it, your plugin code might be able to connect to the DBMS server and talk to the | ||
| DBMS directly. This can avoid the need to do DBMS operations via running Bash/Powershell code on the remote host. | ||
|
|
||
|
|
||
| ### Example | ||
| ```python | ||
| import httplib | ||
| import json | ||
|
|
||
| dbms_port = 5432 | ||
|
|
||
| # Directly contact our DBMS's REST server to get a list of databases | ||
| def list_databases(remote_ip): | ||
| cx = httplib.HTTPConnection(remote_ip, dbms_port) | ||
| cx.request("GET", "/databases") | ||
| response = cx.getresponse() | ||
| return json.loads(response.read()) | ||
| ``` | ||
|
|
||
| What your plugin can access depends entirely on the customer. Some customers will set up their Delphix | ||
| Engines such that plugins have full access to the entire internet. Some will completely restrict the network | ||
| so that the plugin can only access a small handful of remote hosts. | ||
|
|
||
| If your plugin has any specific network requirements, it's recommended to try, in your code, to confirm that these requirements are met. For example, the plugin could make such a check in the | ||
| `discovery.repository()` operation, and throw an error if the check fails. Like any other requirement, this should of course be documented. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,90 @@ | ||
| # Working With Strings | ||
|
|
||
| Unfortunately, Python 2.7 makes it very easy to accidentally write string-related code that will sometimes work, but sometimes fail (especially for people who are not using English). Read on for some tips for how to avoid this. | ||
|
|
||
| ## The Two String Types | ||
| Python 2.7 has two different types that are both called "strings". One represents | ||
| a sequence of **bytes**, and the other represents a sequence of **characters**. | ||
|
|
||
| ```python | ||
| # The default string (aka 'str object') represents bytes | ||
| my_bytes = "This string is a sequence of bytes" | ||
|
|
||
| # A 'Unicode object' represents characters (note the u just before the quote) | ||
| my_characters = u"This string is a sequence of characters" | ||
| ``` | ||
|
|
||
| ## Unicode Strings Are Preferred | ||
|
|
||
| There are a couple of reasons to prefer the "unicode object" over the "str object". | ||
|
|
||
| First, in most cases, we care about characters, and we're not particularly interested in which bytes | ||
| are used to represent those characters. That is, we might care that we have a "letter H" followed by a "letter I", but it's usually irrelevant to us what byte values happen to be used. | ||
|
|
||
| Second, there are lots of different schemes available which give rules for how to represent characters as bytes. These schemes are called "encodings"; some examples include "ASCII", "UTF-8", "Shift-JIS", and "UCS-2". Each encoding uses different rules about which characters are represented by which bytes. | ||
|
|
||
| A "str object" doesn't know anything about encodings... it is just a sequence of bytes. So, when a programmer is working with one of these byte strings, they have to know which encoding rules are in play. | ||
|
|
||
| In order to avoid problems, **we recommend using Unicode strings everywhere** in your plugin code. | ||
|
|
||
| ## Delphix I/O | ||
|
|
||
| Your plugin will sometimes need to send strings back and forth to Delphix code. There are two supported formats for doing this. Any time you receive a string from Delphix, it will be in one of the two following forms. This includes arguments to your plugin operations, and return values from "Delphix Libs" functions. Likewise, any time you send a string to Delphix, it must be in one of these two forms. | ||
|
|
||
| Acceptable forms: | ||
|
|
||
| 1. A Unicode string (recommended) | ||
| 2. A "str object" (byte string) that uses the UTF-8 encoding | ||
|
|
||
| ## Converting Between Types | ||
|
|
||
| Sometimes (hopefully rarely!), you might find yourself needing to convert back and forth between byte strings and character strings. For example, you might need to read or write a file on a remote system that is required to use some specific encoding. Here's how to do that: | ||
|
|
||
| ```python | ||
| # Converting from a character string ("unicode") to a byte string ("str") | ||
| my_utf8_byte_string = my_character_string.encode("utf-8") | ||
| my_utf16_byte_string = my_character_string.encode("utf-16") | ||
|
|
||
| # Converting from a byte string to a character string | ||
| my_character_string1 = my_utf8_byte_string.decode("utf-8") | ||
| my_character_string2 = my_utf16_byte_string.decode("utf-16") | ||
| my_character_string3 = my_ascii_byte_string.decode("ascii") | ||
| ``` | ||
|
|
||
| Things to note: | ||
|
|
||
| - `encode` goes from characters to bytes. `decode` goes from bytes to characters. | ||
| - If you try to `encode` a character string using the `ascii` encoding, but your character string contains non-ascii characters, you'll get an error. More generally: some encodings will error out with some characters. | ||
| - If you don't specify an encoding, Python will supply a default. But, there's a good chance the default will be wrong for your use case. So, always specify the encoding! | ||
| - Don't try to `encode` a byte string. If you do this, Python will "helpfully" insert an implicit `decode` first, which tends to cause very confusing error messages. Likewise, don't try to `decode` a character string. | ||
| - `utf-8` is likely the best encoding to use for most situations. It accepts all characters, does not have issues with byte ordering, and is understood by most systems. This is not true of most other encodings. | ||
|
|
||
| ## Using Non-ASCII characters in Python files | ||
|
|
||
| Python 2.7 source code files are assumed to use the "ASCII" encoding, unless told otherwise. Unfortunately, ASCII is an obsolete encoding that only knows how to deal with a small number of characters, and only really supports American English. | ||
|
|
||
| In order to include non-ASCII characters in your source code, you need to use a different encoding than ASCII, and you need to tell the Python interpreter which encoding you're using. In Python 2.7, this is done with a "magic" comment at the very top of each file. | ||
|
|
||
| Here is an example of the first line of a Python file that uses the UTF-8 encoding: | ||
| ```python | ||
| # -*- coding: utf-8 -*- | ||
| ``` | ||
|
|
||
| If you do not specify an encoding, and the source code contains any non-ASCII characters, you will get errors | ||
| when building the plugin using [dvp build](/References/CLI.md#build) or during the execution of a plugin operation. | ||
|
|
||
| ### Example | ||
|
|
||
| ```python | ||
| # -*- coding: utf-8 -*- | ||
| from dlpx.virtualization.platform import Plugin | ||
| from dlpx.virtualization import libs | ||
| from generated.definitions import RepositoryDefinition | ||
|
|
||
| plugin = Plugin() | ||
|
|
||
| @plugin.discovery.repository() | ||
| def repository_discovery(source_connection): | ||
| # Create a repository with name that uses non-ASCII characters | ||
| return [RepositoryDefinition(name=u"Théâtre")] | ||
| ``` |
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we tell them that they can use any linux x86 compatible libraries?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was a little torn on this. I thought there were probably two good options:
Leave it vague like this. This gives enough clues to people who know what they're doing so that they know that they need to match architectures of binaries. This doesn't really help people who don't already know about binary packages and/or cross-compilation of source code, though.
Put in a ton more information, including examples. This would hopefully give everyone enough information to do what they need to do.
For now, I thought (1) was okay. I figured that we were likely going to be closing in on a real supported solution for 3rd-party libraries soon... and at that point we could expand this doc into something more generally useful.
What do you think?