Giter VIP home page Giter VIP logo

simplivity-python's Introduction

PyPI version Build Status Coverage Status

HPE SimpliVity SDK for Python

This library provides a Python interface to the HPE SimpliVity REST APIs.

HPE SimpliVity is an intelligent hyperconverged platform that speeds application performance, improves efficiency and resiliency, and backs up and restores VMs in seconds.

Installation

From source

Either:

$ git clone https://github.com/HewlettPackard/simplivity-python.git
$ cd simplivity-python
$ python setup.py install --user  # to install in the user directory (~/.local)
$ sudo python setup.py install    # to install globally

Or if using PIP:

$ git clone https://github.com/HewlettPackard/simplivity-python.git
$ cd simplivity-python
$ pip install .

Both installation methods work if you are using virtualenv, which you should be!

From Pypi

$ pip install simplivity

API Implementation

Status of the HPE SimpliVity REST interfaces that have been implemented in this Python library can be found in the Wiki section.

SDK Documentation

The latest version of the SDK documentation can be found in the SDK Documentation section.

Configuration

JSON

Connection properties for accessing the OVC can be set in a JSON file.

Before running the samples or your own scripts, you must create the JSON file. An example can be found at: configuration sample.

Once you have created the JSON file, you can initialize the OVC client:

ovc_client = OVC.from_json_file('/path/config.json')

๐Ÿ”’ Tip: Check the file permissions because the password is stored in clear-text.

Environment Variables

Configuration can also be stored in environment variables:

# Required
export SIMPLIVITYSDK_OVC_IP='10.30.4.45'
export SIMPLIVITYSDK_USERNAME='admin'
export SIMPLIVITYSDK_PASSWORD='secret'

# Optional
export SIMPLIVITYSDK_SSL_CERTIFICATE='<path_to_cert.crt_file>'
export SIMPLIVITYSDK_CONNECTION_TIMEOUT='<connection time-out in seconds>'

๐Ÿ”’ Tip: Make sure no unauthorized person has access to the environment variables, since the password is stored in clear-text.

Once you have defined the environment variables, you can initialize the OVC client using the following code snippet:

ovc_client = OVC.from_environment_variables()

Dictionary

You can also set the configuration using a dictionary. As described above, for authentication you can use username/password:

config = {
    "ip": "10.30.4.45",
    "credentials": {
        "username": "admin",
        "password": "secret"
    }
}

ovc_client_client = OVC(config)

๐Ÿ”’ Tip: Check the file permissions because the password is stored in clear-text.

SSL Server Certificate

To enable the SDK to establish a SSL connection to the SimpliVity OVC, it is necessary to generate a CA certificate file containing the OVC credentials.

  1. Fetch the SimpliVity OVC CA certificate.
$ openssl s_client -showcerts -host <ovc_ip> -port 443
  1. Copy the OVC certificate wrapped with a header line and a footer line into a <file_name>.crt file.
-----BEGIN CERTIFICATE-----
... (OVC certificate in base64 PEM encoding) ...
-----END CERTIFICATE-----
  1. Declare the CA Certificate location when creating a config dictionary.
config = {
    "ip": "172.16.102.82",
    "credentials": {
        "username": "admin",
        "password": "secret"
    },
    "ssl_certificate": "/path/ovc_certificate.crt"
}

SimpliVity Connection Timeout

By default the system timeout is used when connecting to OVC. If you want to change this, then the timeout can be set by either:

  1. Setting the appropriate environment variable:
export SIMPLIVITYSDK_CONNECTION_TIMEOUT='<connection time-out in seconds>'
  1. Setting the time-out in the JSON configuration file using the following syntax:
"timeout": <timeout in seconds>

Contributing and feature requests

Contributing: We welcome your contributions to the Python SDK for HPE SimpliVity. See CONTRIBUTING.md for more details.

Feature Requests: If you have a need that is not met by the current implementation, please let us know (via a new issue). This feedback is crucial for us to deliver a useful product. Do not assume that we have already thought of everything, because we assure you that is not the case.

Testing

When contributing code to this project, we require tests to accompany the code being delivered. That ensures a higher standing of quality, and also helps to avoid minor mistakes and future regressions.

When writing the unit tests, the standard approach we follow is to use the python library unittest.mock to patch all calls that would be made to the OVC and return mocked values.

We have packaged everything required to verify if the code is passing the tests in a tox file. The tox call runs all unit tests against Python 3, runs a flake8 validation, and generates the test coverage report.

To run it, use the following command:

$ tox

You can also check out examples of tests for different resources in the tests folder.

License

This project is licensed under the Apache license. Please see LICENSE for more information.

Version and changes

To view history and notes for this version, view the Changelog.

simplivity-python's People

Contributors

kalpanabhardwaj avatar mumblingmac avatar sijeesh avatar svt-hchaudhari avatar svt-mgawade avatar svt-pchavan avatar svt-vverma avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

simplivity-python's Issues

Policies.create() doesn't correctly pass in the flags

The do_post method takes in the following information (uri, data, timeout, custom_headers, flags).

the policies.create() method passes in the following information (URL, data, timeout, flags) which maps to (uri, data, timeout, custom_headers) meaning that the flags are being passed in as a custom header, and never being passed to the do_post command correctly.

Exception is thrown from connection.py if resp_body is None or empty from method 'do_http'

Exception is thrown from connection.py if resp_body is None or empty from method 'do_http'
Exception:
Traceback (most recent call last):
File "examples/certificates.py", line 52, in
certificate.delete()
File "/home/vverma/.pyenv/versions/3.7.6/lib/python3.7/site-packages/simplivity/resources/certificates.py", line 66, in delete
self._client.do_delete(resource_uri, timeout)
File "/home/vverma/.pyenv/versions/3.7.6/lib/python3.7/site-packages/simplivity/resources/resource.py", line 283, in do_delete
task, body = self._connection.delete(uri, custom_headers=custom_headers)
File "/home/vverma/.pyenv/versions/3.7.6/lib/python3.7/site-packages/simplivity/connection.py", line 172, in delete
return self.__do_rest_call('DELETE', uri, {}, custom_headers=custom_headers)
File "/home/vverma/.pyenv/versions/3.7.6/lib/python3.7/site-packages/simplivity/connection.py", line 203, in __do_rest_call
custom_headers=custom_headers)
File "/home/vverma/.pyenv/versions/3.7.6/lib/python3.7/site-packages/simplivity/connection.py", line 86, in do_http
json_body = json.loads(resp_body.decode('utf-8'))
File "/home/vverma/.pyenv/versions/3.7.6/lib/python3.7/json/init.py", line 348, in loads
return _default_decoder.decode(s)
File "/home/vverma/.pyenv/versions/3.7.6/lib/python3.7/json/decoder.py", line 337, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
File "/home/vverma/.pyenv/versions/3.7.6/lib/python3.7/json/decoder.py", line 355, in raw_decode
raise JSONDecodeError("Expecting value", s, err.value) from None

all unit test cases are not being executed via tox

There appears to be a total of 106 unique unit test cases within the ./tests/unit directory structure

python -m unittest discover executes the 34 test cases directory under ./tests/unit, but skips the 63 tests that are under ./tests/unit/resources.

out of the 63 tests that are under ./tests/unit/resources, 17 currently fail

The solution is to create an empty file called init.py to ./tests/unit/resources directory in order to allow the unittest discover routine to find the test cases

Remote end closed connection without response

It appears that the HTTPSConnection instance might be intended for one transaction with an HTTP server from the documentation.

While using the simplivity-python in an application we have notice that we will received a RemoteDisconnected: Remote end closed connection without response exception while executing configuration operations that have have delay(s).

Backtrace:

Traceback (most recent call last):
  File "/usr/local/lib/python3.7/site-packages/simplivity/connection.py", line 85, in do_http
    resp = self.__connection.getresponse()
  File "/usr/local/lib/python3.7/http/client.py", line 1321, in getresponse
    response.begin()
  File "/usr/local/lib/python3.7/http/client.py", line 296, in begin
    version, status, reason = self._read_status()
  File "/usr/local/lib/python3.7/http/client.py", line 265, in _read_status
    raise RemoteDisconnected("Remote end closed connection without"
http.client.RemoteDisconnected: Remote end closed connection without response
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
  File "policy.py", line 38, in <module>
    policy2 = policies.create("test_sdk2")
  File "/usr/local/lib/python3.7/site-packages/simplivity/resources/policies.py", line 89, in create
    affected_object = self._client.do_post(URL, data, timeout, flags=flags)[0]
  File "/usr/local/lib/python3.7/site-packages/simplivity/resources/resource.py", line 242, in do_post
    task, entity = self._connection.post(uri, data, custom_headers=custom_headers)
  File "/usr/local/lib/python3.7/site-packages/simplivity/connection.py", line 148, in post
    return self.__do_rest_call('POST', uri, body, custom_headers=custom_headers)
  File "/usr/local/lib/python3.7/site-packages/simplivity/connection.py", line 204, in __do_rest_call
    custom_headers=custom_headers)
  File "/usr/local/lib/python3.7/site-packages/simplivity/connection.py", line 89, in do_http
    raise exceptions.HPESimpliVityException(traceback.format_exc())
simplivity.exceptions.HPESimpliVityException: Traceback (most recent call last):
  File "/usr/local/lib/python3.7/site-packages/simplivity/connection.py", line 85, in do_http
    resp = self.__connection.getresponse()
  File "/usr/local/lib/python3.7/http/client.py", line 1321, in getresponse
    response.begin()
  File "/usr/local/lib/python3.7/http/client.py", line 296, in begin
    version, status, reason = self._read_status()
  File "/usr/local/lib/python3.7/http/client.py", line 265, in _read_status
    raise RemoteDisconnected("Remote end closed connection without"
http.client.RemoteDisconnected: Remote end closed connection without response

Simplified Code Sample

config = {
    "ip": <IP_ADDRESS>,
    "credentials": {
        "username": <USERNAME>,
        "password": <PASSWORD>,
    },
}
ovc = OVC(config)
policies = ovc.policies
print("creating policy1")
policy1 = policies.create("test_sdk1")
time.sleep(120)
print("creating policy2")
policy2 = policies.create("test_sdk2")
print("\n\ndelete policy")
policy1.delete()
policy2.delete()

Error Handling for Invalid Token doesn't work

There are a couple of issues that I have discovered while troubleshooting other issues.

  • path, and body are passed into do_http, modified early on in the method, and then the new values are used to attempt to re-issue a command if the error is an invalid_token
  • the return tuple is not processed inside the if statement for the invalid_token code
    self.login(self._username, self._password)
    self.do_http(method, path, body, custom_headers)
    ** note: this wasn't caught during the unit test because it wasn't checked

Virtual Machine __refresh overwrites the data incorrectly.

The __refresh method incorrectly replaces self.data with the response without stripping off the DATA_FIELD before hand.

Here is the virtual machine data from the get_all method

<simplivity.resources.virtual_machines.VirtualMachine object at 0x7f7ba98fd160>
{   'app_aware_vm_status': 'UNKNOWN',
    'cluster_group_ids': <DATA REMOVED>,
    'compute_cluster_parent_hypervisor_object_id': <DATA REMOVED>,
    'compute_cluster_parent_name': <DATA REMOVED>,
    'created_at': '2020-03-17T22:24:08Z',
    'datastore_id': <DATA REMOVED>,
    'datastore_name': <DATA REMOVED>,
    'deleted_at': 'NA',
    'host_id': <DATA REMOVED>,
    'hypervisor_management_system': <DATA REMOVED>,
    'hypervisor_management_system_name': <DATA REMOVED>,
    'hypervisor_object_id': <DATA REMOVED>,
    'hypervisor_type': 'VSPHERE',
    'id': <DATA REMOVED>,
    'name': 'ubuntu-bionic-18.04-cloudimg-20200218',
    'omnistack_cluster_id': <DATA REMOVED>,
    'omnistack_cluster_name': '<DATA REMOVED>,
    'policy_id': <DATA REMOVED>,
    'policy_name': <DATA REMOVED>,
    'replica_set': [   {   'id': <DATA REMOVED>,
                           'role': 'SECONDARY'},
                       {   'id': <DATA REMOVED>,
                           'role': 'PRIMARY'}],
    'state': 'ALIVE'} 

Here is the virtual machine data after a refresh occurs

<simplivity.resources.virtual_machines.VirtualMachine object at 0x7f7ba98fd160>
{   'virtual_machine': {   'app_aware_vm_status': 'UNKNOWN',
                           'cluster_group_ids': <DATA REMOVED>,
                           'compute_cluster_parent_hypervisor_object_id': <DATA REMOVED>,
                           'compute_cluster_parent_name': <DATA REMOVED>,
                           'created_at': '2020-03-17T22:24:08Z',
                           'datastore_id': <DATA REMOVED>,
                           'datastore_name': <DATA REMOVED>,
                           'deleted_at': 'NA',
                           'ha_resynchronization_progress': 100,
                           'ha_status': 'SAFE',
                           'host_id': <DATA REMOVED>,
                           'host_name': <DATA REMOVED>,
                           'hypervisor_allocated_capacity': 12552624407,
                           'hypervisor_allocated_cpu': -1,
                           'hypervisor_consumed_cpu': 0,
                           'hypervisor_consumed_memory': 0,
                           'hypervisor_cpu_count': 1,
                           'hypervisor_folder_name': <DATA REMOVED>,
                           'hypervisor_free_space': 11460194304,
                           'hypervisor_instance_id': <DATA REMOVED>,
                           'hypervisor_is_template': False,
                           'hypervisor_managed_by': '',
                           'hypervisor_management_system': <DATA REMOVED>,
                           'hypervisor_management_system_name': <DATA REMOVED>,
                           'hypervisor_object_id': <DATA REMOVED>,
                           'hypervisor_total_memory': 1024,
                           'hypervisor_type': 'VSPHERE',
                           'hypervisor_uuid': <DATA REMOVED>,
                           'hypervisor_virtual_disk_count': 1,
                           'hypervisor_virtual_machine_power_state': 'OFF',
                           'id': <DATA REMOVED>,
                           'modified_at': 'Thu Jan 01 00:00:00 GMT 1970',
                           'name': 'ubuntu-bionic-18.04-cloudimg-20200218',
                           'omnistack_cluster_id': <DATA REMOVED>,
                           'omnistack_cluster_name': <DATA REMOVED>,
                           'policy_id': <DATA REMOVED>,
                           'policy_name': <DATA REMOVED>,
                           'replica_set': [   {   'id': <DATA REMOVED>,
                                                  'role': 'PRIMARY'},
                                              {   'id': <DATA REMOVED>,
                                                  'role': 'SECONDARY'}],
                           'state': 'ALIVE'}} 

policies.get_by_name("Fixed Default Backup Policy")

policies.get_by_name("Fixed Default Backup Policy") raises a json.decoder.JSONDecodeError due to invalid url encoding.

Traceback (most recent call last): File "demo.py", line 40, in <module> policies.get_by_name("Fixed Default Backup Policy") File "/home/kmcdaniel/bitbucket/simplivity-python/simplivity/resources/resource.py", line 307, in get_by_name resources = self.get_all(filters={'name': name}) File "/home/kmcdaniel/bitbucket/simplivity-python/simplivity/resources/policies.py", line 63, in get_all case_sensitive=case_sensitive) File "/home/kmcdaniel/bitbucket/simplivity-python/simplivity/resources/resource.py", line 196, in get_all response = self._connection.get(url) File "/home/kmcdaniel/bitbucket/simplivity-python/simplivity/connection.py", line 130, in get resp, body = self.do_http('GET', url, '') File "/home/kmcdaniel/bitbucket/simplivity-python/simplivity/connection.py", line 87, in do_http body = json.loads(response.decode('utf-8')) File "/home/kmcdaniel/.pyenv/versions/3.7.3/lib/python3.7/json/__init__.py", line 348, in loads return _default_decoder.decode(s) File "/home/kmcdaniel/.pyenv/versions/3.7.3/lib/python3.7/json/decoder.py", line 337, in decode obj, end = self.raw_decode(s, idx=_w(s, 0).end()) File "/home/kmcdaniel/.pyenv/versions/3.7.3/lib/python3.7/json/decoder.py", line 355, in raw_decode raise JSONDecodeError("Expecting value", s, err.value) from None json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

invalid exception handling within ovc_client.py

The two exceptions that are implemented in ovc_client.py are currently not unit tested and are non-functional areas of code.

The first exception isn't raised

The second exception doesn't exists due to a typo

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.