Getting Started¶
Note
As a convention throughout this documentation, whenever we write an entity such as pool
, volume
, system
etc., it will always refer to a Python object – never to a name string or to an object identifier. When we want to indicate a name or an id we will name variables accordingly (e.g. volume_id
, pool_name
etc.).
Installation¶
Installing InfiniSDK is done by using pip
:
$ pip install infinisdk
Note
Depending on your Python installation, the above command might require root privileges
See also
For more information on pip and how to use it to install Python packages, see https://pip.pypa.io/en/stable/
Creating the InfiniBox Object¶
In your Python interpreter, import the infinisdk.InfiniBox
class, and initialize it with your system address:
>>> from infinisdk import InfiniBox
>>> system = InfiniBox(SYSTEM_ADDRESS)
Note
SYSTEM_ADDRESS
can be a hostname for your system’s management address, or an IP address
SSL is disabled by default, but can be easily turned on by passing use_ssl=True
to the system constructor:
>>> system = InfiniBox(SYSTEM_ADDRESS, use_ssl=True)
Note
By default, constructing a system does not send any traffic or API calls to the system. Only performing actual actions or queries does.
Authentication¶
Authentication information can also be specified via the constructor:
>>> system = InfiniBox(SYSTEM_ADDRESS, auth=("admin", "password"))
Note that you need to explicitly call login
to actually log in to the system:
>>> system.login()
<Response [200]>
Another way authentication information can be provided is through an .ini
file. Create a file named ~/.infinidat/infinisdk.ini
, with the following structure:
[infinibox]
username=admin
password=password
Now constructing an InfiniBox object will use the credentials above by default. You can also specify authorization for specific system, by adding sections to the .ini file titled infinibox:<system name>
:
[infinibox] # will be used for default
username=defaultlogin
password=defaultpassword
[infinibox:system01] # will be used for interacting with the InfiniBox named 'system01'
username=other
password=otherpassword
Logging¶
InfiniSDK uses Logbook for logging, and by default all logs are emitted to the standard error stream.
The emitted logs also include the full debug outputs of the API calls made to the system, which might be a bit too much in some cases, overflowing your console unnecessarily. If you prefer less verbosity, you can set up a different logging scheme. For instance, the following code will only emit INFO
logs to the console:
>>> import logbook
>>> import sys
>>> with logbook.NestedSetup([
... logbook.NullHandler(),
... logbook.StreamHandler(sys.stderr, level=logbook.INFO)]):
... pass # your code here
See also
Approving Dangerous Operations¶
By default, InfiniSDK performs operations regardless of the level of caution required for them. When a user uses a CLI or a GUI, Infinidat products often require confirmation before carrying out some dangerous operations requiring extra attention.
If you want your script to interactively ask the user for confirmation for such operations, use the set_interactive_approval()
method:
>>> system.api.set_interactive_approval()
You can also turn off approvals temporarily, causing your script to fail with an exception in case dangerous operations are about to be carried out:
>>> with system.api.get_unapproved_context():
... pass # operations here
Representing API Entities¶
InfiniSDK provides reflection for objects or entities defined on the system in the form of Pythonic objects. This makes creation, deletion and manipulation of objects easier. Supported objects are defined as Python classes such as infinisdk.infinibox.volume.Volume
or infinisdk.infinibox.pool.Pool
, and are accessed more easily through collection proxies, such as system.volumes, system.pools etc. For each supported object type X
, there exists system.Xs
.
The following examples illustrate how to use those proxies.
Creating Objects¶
Creation of objects can be done easily via the create
method. InfiniSDK provides defaults for all required fields that can be autogenerated. For instance, creating a pool can be done via system.pools.create():
>>> pool = system.pools.create()
Note
the create shortcut used above is a very thin wrapper around the create method of the Pool class
. All it does is automatically assign the “right” system to the first argument.
Object Attributes¶
Once an object is obtained (either by creation or querying as described further down), it can be inspected for its attributes or manipulated in various ways. This is done using getter/setter methods. For most used names, there are direct setters and getters:
>>> pool.update_name('new_name')
>>> pool.get_name() == 'new_name'
True
All fields can be accessed via the SystemObject.get_field()
/ SystemObject.update_field()
methods:
>>> pool.update_field('name', 'yet_another_name')
>>> pool.get_field('name') == 'yet_another_name'
True
Caching¶
Whenever an object attribute is fetched, it is cached for later use. By default, getting fields always fetches them from the cache of the requested object.
In case you need to fetch an up-to-date value for a field, there are several options:
Use
from_cache=False
:>>> print(pool.get_field('name', from_cache=False)) yet_another_name
The above forces InfiniSDK to fetch the name from the system regardless of the cache
Disable caching completely:
>>> system.disable_caching()
Storage Capacity Handling¶
InfiniSDK reflects data sizes using the capacity
module, allowing easy computations and manipulations of data sizes, including units:
>>> from capacity import GiB
>>> size = pool.get_virtual_capacity()
>>> print(size)
1 TB
>>> print(size * 2)
2 TB
>>> print(size // GiB)
931
Querying Objects¶
Querying objects of various types is done relatively easily through InfiniSDK. The InfiniBox system exposes collection proxies, which provide iteration and filtering. Here’s an example of querying all volumes on a system:
>>> system.volumes.count()
0
>>> system.volumes.to_list()
[]
See also
Deleting Objects¶
Deleting objects can be done by the delete
method, which is available for the vast majority of the object types.
>>> host = system.hosts.create()
>>> host.delete() # <-- host gets deleted
Note
The delete
method usually doesn’t take care of indirect deletion needed to fullfill the request (like deleting volumes inside pools). This is a design decision that has been made to prevent unintended operations from being unwittingly made on the user’s behalf.
Accessing HTTP/REST API Directly¶
InfiniSDK supports calling the HTTP/REST API of the system directly:
>>> response = system.api.get('system/product_id')
The above accesses /api/rest/system/product_id
. API.get()
, API.post()
, API.delete()
and API.put()
all return Response
objects. Results can be fetched by Response.get_result()
:
>>> print(response.get_result())
INFINIBOX
You can always access the response belonging to requests through .response
:
>>> response.response.status_code
200
By default, requests are checked for success. This behavior can be overriden by providing assert_success=False
:
>>> response = system.api.get('nonexistent/path', assert_success=False)
>>> response.response.status_code
404