Skip to content
This repository has been archived by the owner on Apr 27, 2022. It is now read-only.

Client Library HIL | query calls #617

Merged
merged 84 commits into from
Apr 24, 2017
Merged
Show file tree
Hide file tree
Changes from 82 commits
Commits
Show all changes
84 commits
Select commit Hold shift + click to select a range
e75786c
client library support for HIL query calls.
SahilTikale Jun 6, 2016
61bb87d
Adds files containing common code to build client library.
SahilTikale Jun 20, 2016
3d8ca6d
Merge branch 'master' into HILclientlib-querycalls
SahilTikale Jun 20, 2016
ee5aa40
Adds client library support for query calls
SahilTikale Jun 20, 2016
529b37c
Adds client support to CLI.
SahilTikale Jul 3, 2016
e5cdad3
Adds
SahilTikale Jul 5, 2016
060a55e
Adds unit tests and some code refactor.
SahilTikale Jul 5, 2016
5237d61
Addresses unit tests of client Base class
SahilTikale Jul 5, 2016
dc4ffea
Merge branch 'master' into HILclientlib-querycalls
SahilTikale Jul 5, 2016
cae9dd4
Supports new call list_nodes in place of list_free_nodes.
SahilTikale Jul 5, 2016
06b197a
adds __init__ file
SahilTikale Jul 25, 2016
f9eb580
making unit tests to work
SahilTikale Jul 26, 2016
2e63285
Includes a clean way to
SahilTikale Aug 8, 2016
f36ac1f
unit tests pass.
SahilTikale Aug 8, 2016
ddf43d4
Merge remote-tracking branch 'origin/master' into HILclientlib-queryc…
SahilTikale Aug 8, 2016
595c30d
Fixes unit tests
SahilTikale Aug 8, 2016
b0106ac
increasing delay to fix tests
SahilTikale Aug 8, 2016
27a619f
fixes CI test
SahilTikale Aug 10, 2016
e04d629
fixing CI tests
SahilTikale Aug 10, 2016
ae7c278
Merge remote-tracking branch 'origin/master' into HILclientlib-queryc…
SahilTikale Oct 11, 2016
7cddc95
Fixes call list_nodes in the client library. Had the same issue as fi…
SahilTikale Oct 11, 2016
ef94c61
Adding add/delete operations and tests related to project
SahilTikale Oct 11, 2016
e5f3150
Adding network module to client library
SahilTikale Oct 11, 2016
c07cc78
Adds client library support and unit tests for
SahilTikale Oct 12, 2016
16de104
Adds node operations.
SahilTikale Oct 17, 2016
404a37b
Adds
SahilTikale Oct 17, 2016
c3d54bf
syncing with upstream master
SahilTikale Nov 7, 2016
16bb93c
This commit makes the necessary changes to support keystone as a backend
SahilTikale Nov 9, 2016
da671fc
Removes old client Library
SahilTikale Nov 9, 2016
2e164cd
Fixes some broken tests. Makes tests/unit/client.py pep8 complaint.
SahilTikale Nov 9, 2016
e132ea6
1st pass at Integrating keystone authentication with client library.
SahilTikale Nov 9, 2016
485ced3
Adds user operations related calls in client library and cli.
SahilTikale Dec 11, 2016
b9ffe29
Adds client library calls for network, node and cli support for them.
SahilTikale Dec 12, 2016
ba23ded
Adds calls node connect network and switch related calls.
SahilTikale Dec 14, 2016
174cec7
minor changes
SahilTikale Dec 14, 2016
347090c
Adds client library calls for most of the api calls
SahilTikale Dec 22, 2016
bcbcd12
Fixes console calls in node.py and adds unit tests
SahilTikale Dec 22, 2016
37cf4b0
adds more unit tests
SahilTikale Dec 22, 2016
4d50af5
Merge branch 'master' into HILclientlib-querycalls
SahilTikale Dec 22, 2016
21f9d13
addresses @zenhacks comments
SahilTikale Dec 22, 2016
559bc40
fixed failing test
naved001 Jan 13, 2017
d65ed0f
fixed pep8 errors in all files except test/unit/client.py
meng-sun Jan 14, 2017
16bbefd
Merge remote-tracking branch 'upstream/HILclientlib-querycalls' into …
meng-sun Jan 14, 2017
bac7d39
pep8 issues fixed
gfaline Jan 17, 2017
5c29a76
Merge pull request #2 from meng-sun/HILclientlib-querycalls
gfaline Jan 17, 2017
98967cd
fixed a couple more pep8 errors
gfaline Jan 17, 2017
0556f3d
fixed pep8 issues
gfaline Jan 17, 2017
14cedef
Merge pull request #1 from naved001/HILclientlib-querycalls
henn Jan 18, 2017
7b6523e
type error fix that aligns with pep8 fix
meng-sun Jan 18, 2017
7fe634d
assertionError problems fixed
meng-sun Jan 19, 2017
0213717
Merge pull request #3 from meng-sun/HILclientlib-querycalls
meng-sun Jan 19, 2017
d1c9eba
Merge pull request #4 from naved001/naved/sahil
SahilTikale Jan 31, 2017
e22c210
Addresses comments from reviewers.
SahilTikale Feb 1, 2017
5e30397
fixing pep8 issues
SahilTikale Feb 1, 2017
b45ec80
Includes code refactored to reduce verbosity as recommended by @zenhack
SahilTikale Feb 16, 2017
d20c55f
removing non-essential code
SahilTikale Feb 16, 2017
adc94d0
removes import that is not required anymore
SahilTikale Feb 16, 2017
493ae42
Merge remote-tracking branch 'origin/master' into HILclientlib-queryc…
SahilTikale Feb 16, 2017
290e150
Refactors cli.py to reduce repetitive code
SahilTikale Feb 18, 2017
a54ce5e
Fixes the broken test due to recent merging with the master
SahilTikale Feb 19, 2017
b1b3e97
Fixes the broken test due to recent merging with the master
SahilTikale Feb 19, 2017
de9ddeb
Refactors client library code to reduce code verbosity.
SahilTikale Feb 19, 2017
d266f4d
Minor refactoring. moving to only for methods.
SahilTikale Feb 23, 2017
a8a0a71
Fixes tests
SahilTikale Feb 27, 2017
df915fd
Updates setup.py to install dependencies to support keystone.
SahilTikale Feb 28, 2017
e05786f
Makes changes suggested by @zenhack.
SahilTikale Feb 28, 2017
3b1ece8
Fixes doc string and other minor changes
SahilTikale Mar 1, 2017
8a33ed0
Merge branch 'master' into HILclientlib-querycalls
SahilTikale Mar 20, 2017
6a8b932
Changes client library to accept a complete object
SahilTikale Mar 20, 2017
42bd4dd
Fixes failing tests,
SahilTikale Mar 20, 2017
c7195a1
minor changes
SahilTikale Mar 20, 2017
67ba238
Fixes cli integration test, Puts appropriate comments in cli.py
SahilTikale Mar 22, 2017
f48e608
minor changes, moving text from docstring to comment
SahilTikale Mar 23, 2017
696f3ef
fixes integration tests
SahilTikale Mar 27, 2017
5786e37
Addresses all the changes recommended by reviewers.
SahilTikale Apr 2, 2017
b01e176
improves tests, removes redundant code
SahilTikale Apr 4, 2017
cca1c99
fixes a tedious test.
SahilTikale Apr 4, 2017
d6e0247
Updated with comment and increased time to avoid a potential race con…
SahilTikale Apr 5, 2017
82a9044
solves the race condition for network tests.
SahilTikale Apr 6, 2017
a1ff5b4
uses sqlalchemy to query networkingaction, to avoid race condition in…
SahilTikale Apr 10, 2017
1cd832e
refactors . Addresses other suggestions by reviewers.
SahilTikale Apr 14, 2017
22800ab
Improves tests, provides explicit message for time out. Moves imports…
SahilTikale Apr 18, 2017
157e518
minorly improves
SahilTikale Apr 20, 2017
922437f
Catches error of not setting HAAS_ENDPOINT.
SahilTikale Apr 21, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
290 changes: 109 additions & 181 deletions haas/cli.py

Large diffs are not rendered by default.

Empty file added haas/client/__init__.py
Empty file.
49 changes: 49 additions & 0 deletions haas/client/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
""" This module implements the HaaS client library. """

import requests
import os
import json
from urlparse import urljoin


class FailedAPICallException(Exception):
pass


class ClientBase(object):
"""Main class which contains all the methods to

-- ensure input complies to API requisites
-- generates correct format for server API on behalf of the client
-- parses output from received from the server.
In case of errors recieved from server, it will generate appropriate
appropriate message.
"""

def __init__(self, endpoint, httpClient):
""" Initialize an instance of the library with following parameters.

endpoint: stands for the http endpoint eg. endpoint=http://127.0.0.1
sess: depending on the authentication backend (db vs keystone) the
parameters required to make up the session vary.
user: username as which you wish to connect to HaaS
Currently all this information is fetched from the user's environment.
"""
self.endpoint = endpoint
self.httpClient = httpClient

def object_url(self, *args):
"""Generate URL from combining endpoint and args as relative URL"""
rel = "/".join(args)
url = urljoin(self.endpoint, rel)
return url

def check_response(self, response):
if response.ok:
if response.request.method == 'GET':
return response.json()
else: # For methods PUT, POST, DELETE
return
else:
e = response.json()
raise FailedAPICallException(e['msg'])
108 changes: 108 additions & 0 deletions haas/client/client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
from haas.client.base import ClientBase
from haas.client.node import Node
from haas.client.project import Project
from haas.client.switch import Switch
from haas.client.switch import Port
from haas.client.network import Network
from haas.client.user import User
import abc
import requests

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

blank lines

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed.


class HTTPClient(object):
"""An HTTP client.

Makes HTTP requests on behalf of the HaaS CLI. Responsible for adding
authentication information to the request.
"""

__metaclass__ = abc.ABCMeta

@abc.abstractmethod
def request(method, url, data=None, params=None):
"""Make an HTTP request

Makes an HTTP request on URL `url` with method `method`, request body
`data`(if supplied) and query parameter `params`(if supplied). May add
authentication or other backend-specific information to the request.

Parameters
----------

method : str
The HTTP method to use, e.g. 'GET', 'PUT', 'POST'...
url : str
The URL to act on
data : str, optional
The body of the request
params : dictionary, optional
The query parameter, e.g. {'key1': 'val1', 'key2': 'val2'},
dictionary key can't be `None`

Returns
-------

requests.Response
The HTTP response
"""


class RequestsHTTPClient(requests.Session, HTTPClient):
"""An HTTPClient which uses the requests library.

Note that this doesn't do anything over `requests.Session`; that
class already implements the required interface. We declare it only
for clarity.
"""


class KeystoneHTTPClient(HTTPClient):
"""An HTTPClient which authenticates with Keystone.

This uses an instance of python-keystoneclient's Session class
to do its work.
"""

def __init__(self, session):
"""Create a KeystoneHTTPClient

Parameters
----------

session : keystoneauth1.Session
A keystone session to make the requests with
"""
self.session = session

def request(self, method, url, data=None, params=None):
"""Make an HTTP request using keystone for authentication.

Smooths over the differences between python-keystoneclient's
request method that specified by HTTPClient
"""
# We have to import this here, since we can't assume the library
# is available from global scope.
from keystoneauth1.exceptions.http import HttpError

try:
# The order of these parameters is different that what
# we expect, but the names are the same:
return self.session.request(method=method,
url=url,
data=data,
params=params)
except HttpError as e:
return e.response


class Client(object):

def __init__(self, endpoint, httpClient):
self.httpClient = httpClient
self.endpoint = endpoint
self.node = Node(self.endpoint, self.httpClient)
self.project = Project(self.endpoint, self.httpClient)
self.switch = Switch(self.endpoint, self.httpClient)
self.port = Port(self.endpoint, self.httpClient)
self.network = Network(self.endpoint, self.httpClient)
self.user = User(self.endpoint, self.httpClient)
52 changes: 52 additions & 0 deletions haas/client/network.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import json
from haas.client.base import ClientBase


class Network(ClientBase):
"""Consists of calls to query and manipulate network related

objects and relations.
"""

def list(self):
"""Lists all projects under HIL """
url = self.object_url('networks')
return self.check_response(self.httpClient.request("GET", url))

def show(self, network):
"""Shows attributes of a network. """
url = self.object_url('network', network)
return self.check_response(self.httpClient.request("GET", url))

def create(self, network, owner, access, net_id):
"""Create a link-layer <network>.

See docs/networks.md for details.
"""
url = self.object_url('network', network)
payload = json.dumps({
'owner': owner, 'access': access,
'net_id': net_id
})
return self.check_response(
self.httpClient.request("PUT", url, data=payload)
)

def delete(self, network):
"""Delete a <network>. """
url = self.object_url('network', network)
return self.check_response(self.httpClient.request("DELETE", url))

def grant_access(self, project, network):
"""Grants <project> access to <network>. """
url = self.object_url(
'network', network, 'access', project
)
return self.check_response(self.httpClient.request("PUT", url))

def revoke_access(self, project, network):
"""Removes access of <network> from <project>. """
url = self.object_url(
'network', network, 'access', project
)
return self.check_response(self.httpClient.request("DELETE", url))
98 changes: 98 additions & 0 deletions haas/client/node.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import json
from haas.client.base import ClientBase


class Node(ClientBase):
"""Consists of calls to query and manipulate node related

objects and relations.
"""

def list(self, is_free):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should is_free have a default (like maybe False)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I checked the cli, client and api code for this call. CLI rejects any other options other than free and all. But api and client library do not have any such restrictions. I mean in absence of the check done at CLI, the API would respond to any string as if it was keyword all. I believe this should be fixed at API level.

"""List all nodes that HIL manages """
url = self.object_url('nodes', is_free)
return self.check_response(self.httpClient.request('GET', url))

def show(self, node_name):
"""Shows attributes of a given node """
url = self.object_url('node', node_name)
return self.check_response(self.httpClient.request('GET', url))

def register(self, node, subtype, *args):
"""Register a node with appropriate OBM driver. """
# Registering a node requires apriori knowledge of the
# available OBM driver and its corresponding arguments.
# We assume that the HIL administrator is aware as to which
# Node requires which OBM, and knows arguments required
# for successful node registration.

obm_api = "http://schema.massopencloud.org/haas/v0/obm/"
obm_types = ["ipmi", "mock"]
# FIXME: In future obm_types should be dynamically fetched.
# We need a new api call for querying available
# and currently active drivers for HIL
raise NotImplementedError

def delete(self, node_name):
"""Deletes the node from database. """
url = self.object_url('node', node_name)
return check_response(self.httpClient.request('DELETE', url))

def power_cycle(self, node_name):
"""Power cycles the <node> """
url = self.object_url('node', node_name, 'power_cycle')
return self.check_response(self.httpClient.request('POST', url))

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

blank lines

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed it.

def power_off(self, node_name):
"""Power offs the <node> """
url = self.object_url('node', node_name, 'power_off')
return self.check_response(self.httpClient.request('POST', url))

def add_nic(self, node_name, nic_name, macaddr):
"""Add a <nic> to <node>"""
url = self.object_url('node', node_name, 'nic', nic_name)
payload = json.dumps({'macaddr': macaddr})
return self.check_response(
self.httpClient.request('PUT', url, data=payload)
)

def remove_nic(self, node_name, nic_name):
"""Remove a <nic> from <node>"""
url = self.object_url('node', node_name, 'nic', nic_name)
return self.check_response(self.httpClient.request('DELETE', url))

def connect_network(self, node, nic, network, channel):
"""Connect <node> to <network> on given <nic> and <channel>"""
url = self.object_url(
'node', node, 'nic', nic, 'connect_network'
)
payload = json.dumps({
'network': network, 'channel': channel
})
return self.check_response(
self.httpClient.request('POST', url, data=payload)
)

def detach_network(self, node, nic, network):
"""Disconnect <node> from <network> on the given <nic>. """
url = self.object_url(
'node', node, 'nic', nic, 'detach_network'
)
payload = json.dumps({'network': network})
return self.check_response(
self.httpClient.request('POST', url, data=payload)
)

def show_console(self, node):
"""Display console log for <node> """
raise NotImplementedError

def start_console(self, node):
"""Start logging console output from <node> """
url = self.object_url('node', node, 'console')
return self.check_response(self.httpClient.request('PUT', url))

def stop_console(self, node):
"""Stop logging console output from <node> and delete the log"""
url = self.object_url('node', node, 'console')
return self.check_response(self.httpClient.request('DELETE', url))
55 changes: 55 additions & 0 deletions haas/client/project.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import json
from haas.client.base import ClientBase


class Project(ClientBase):
"""Consists of calls to query and manipulate project related

objects and relations.
"""

def list(self):
"""Lists all projects under HIL """

url = self.object_url('/projects')
return self.check_response(self.httpClient.request("GET", url))

def nodes_in(self, project_name):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we rename this and the next one to nodes() and networks() ?

"""Lists nodes allocated to project <project_name> """
url = self.object_url('project', project_name, 'nodes')
return self.check_response(self.httpClient.request("GET", url))

def networks_in(self, project_name):
"""Lists nodes allocated to project <project_name> """
url = self.object_url(
'project', project_name, 'networks'
)
return self.check_response(self.httpClient.request("GET", url))

def create(self, project_name):
"""Creates a project named <project_name> """
url = self.object_url('project', project_name)
return self.check_response(self.httpClient.request("PUT", url))

def delete(self, project_name):
"""Deletes a project named <project_name> """
url = self.object_url('project', project_name)
return self.check_response(self.httpClient.request("DELETE", url))

def connect(self, project_name, node_name):
"""Adds a node to a project. """
url = self.object_url(
'project', project_name, 'connect_node'
)
self.payload = json.dumps({'node': node_name})
return self.check_response(
self.httpClient.request("POST", url, data=self.payload)
)

def detach(self, project_name, node_name):
"""Adds a node to a project. """
url = self.object_url('project', project_name, 'detach_node')
self.payload = json.dumps({'node': node_name})
return self.check_response(
self.httpClient.request("POST", url, data=self.payload)
)
Loading