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

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:

  1. 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

  2. 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

Querying Objects

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