#!/usr/bin/env python
#
# Copyright (c) 2013 In-Q-Tel, Inc/Lab41, All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
This module is the web server for running the REST API of Hemlock.
Created on 20 August 2013
@author: Charlie Lewis
"""
import ast
import os
import pexpect
import web
[docs]class Hemlock_REST():
"""
This class is responsible for initializing the urls and web server.
"""
def __init__(self, port=8080, host="0.0.0.0"):
# !! TODO check for environment variables for hemlock.py
# !! TODO needs to be able to use no_couchbase flag
urls = (
'/add/client/(.*)/schedule/(.*)', 'add',
'/add/schedule/(.*)/client/(.*)', 'add',
'/add/system/(.*)/tenant/(.*)', 'add',
'/add/user/(.*)/role/(.*)', 'add',
'/add/user/(.*)/tenant/(.*)', 'add',
'/change/schedule/(.*)/server/(.*)', 'change',
'/create/role', 'create',
'/create/schedule_server', 'create',
'/create/tenant', 'create',
'/create/user', 'create',
'/delete/role/(.*)', 'delete',
'/delete/schedule_server/(.*)', 'delete',
'/delete/schedule/(.*)', 'delete',
'/delete/tenant/(.*)', 'delete',
'/delete/user/(.*)', 'delete',
'/deregister/local-system/(.*)', 'deregister',
'/deregister/remote-system/(.*)', 'deregister',
'/get/client/(.*)', 'get',
'/get/role/(.*)', 'get',
'/get/schedule_server/(.*)', 'get',
'/get/schedule/(.*)', 'get',
'/get/system/(.*)', 'get',
'/get/tenant/(.*)', 'get',
'/get/user/(.*)', 'get',
'/list/all', 'list1',
'/list/clients', 'list1',
'/list/roles', 'list1',
'/list/schedule_servers', 'list1',
'/list/schedules', 'list1',
'/list/systems', 'list1',
'/list/tenants', 'list1',
'/list/users', 'list1',
'/list/client/schedules/(.*)', 'list2',
'/list/client/systems/(.*)', 'list2',
'/list/role/users/(.*)', 'list2',
'/list/schedule/clients/(.*)', 'list2',
'/list/system/clients/(.*)', 'list2',
'/list/system/tenants/(.*)', 'list2',
'/list/tenant/systems/(.*)', 'list2',
'/list/tenant/users/(.*)', 'list2',
'/list/user/roles/(.*)', 'list2',
'/list/user/tenants/(.*)', 'list2',
'/purge/client/(.*)', 'delete',
'/query', 'query',
'/run/client/(.*)/(.*)', 'run',
'/register/local-system', 'register',
'/register/remote-system', 'register',
'/remove/client/(.*)/schedule/(.*)', 'remove',
'/remove/schedule/(.*)/client/(.*)', 'remove',
'/remove/system/(.*)/tenant/(.*)', 'remove',
'/remove/user/(.*)/role/(.*)', 'remove',
'/remove/user/(.*)/tenant/(.*)', 'remove',
'/schedule/client', 'create',
'/store/client', 'create',
'/store/hemlock-server', 'create',
'/favicon.ico','favicon'
)
app = web.application(urls, globals())
web.httpserver.runsimple(app.wsgifunc(), (host, port))
[docs]class favicon:
"""
This class is responsible for rendering the favicon.
"""
[docs] def GET(self):
"""
GETs the favicon for http requests.
:return: returns the favicon
"""
f = open("static/favicon.ico", 'rb')
web.header("Content-Type","image/x-icon")
return f.read()
[docs]class query:
"""
This class is responsible for all data query requests.
"""
[docs] def POST(self):
"""
POSTs the authentication for the query and returns the query respond
specific to the user credentials provided.
:return: returns the results of the query
"""
data = web.data()
data = ast.literal_eval(data)
# !! TODO add no_couchbase flag
cmd = "hemlock query-data --user "+data['user']+" --query "+data['query']
child = pexpect.spawn(cmd)
child.expect('Password:')
child.sendline(data['password'])
return child.read()
[docs]class fields:
"""
This class is responsible for all requests about data fields or schemas.
"""
[docs] def GET(self):
"""
GETs the schemas of all data that is stored in Hemlock.
:return: returns the fields in all schemas stored in Hemlock
"""
true = True
false = False
null = None
mapping = urllib2.urlopen("http://localhost:9200/_mapping").read()
mapping = json.loads(mapping)
return sorted(mapping["hemlock"]["couchbaseDocument"]["properties"]["doc"]["properties"].keys())
[docs]class add:
"""
This class is responsible for all API actions that involve adding something
to something else.
"""
[docs] def GET(self, first, second):
"""
Performs the add actions of the API.
:param first: the uuid of the first part of the action
:param second: the uuid of the second part of the action
:return: returns the result of the action
"""
if "system" in web.ctx['fullpath']:
cmd = "hemlock system-add-tenant --uuid "+first+" --tenant_id "+second
elif "add/client" in web.ctx['fullpath']:
cmd = "hemlock client-add-schedule --uuid "+first+" --schedule_id "+second
elif "add/schedule" in web.ctx['fullpath']:
cmd = "hemlock schedule-add-client --uuid "+first+" --client_id "+second
elif "role" in web.ctx['fullpath']:
cmd = "hemlock user-add-role --uuid "+first+" --role_id "+second
elif "user" in web.ctx['fullpath']:
cmd = "hemlock user-add-tenant --uuid "+first+" --tenant_id "+second
return os.popen(cmd).read()
[docs]class change:
"""
This class is responsible for changing the server that a schedule runs on.
"""
[docs] def GET(self, first, second):
"""
Performs the change action of the API.
:param first: the uuid of the schedule to change
:param second: the uuid of the server the schedule is being changed to
:return: returns the result of the action
"""
if "server" in web.ctx['fullpath']:
cmd = "hemlock schedule-change-server --uuid "+first+" --schedule_server_id "+second
return os.popen(cmd).read()
[docs]class create:
"""
This class is responsible for all API actions that involve creating
someting.
"""
[docs] def POST(self):
"""
POSTs the create actions of the API.
:return: returns the result of the action
"""
data = web.data()
data = ast.literal_eval(data)
if "role" in web.ctx['fullpath']:
cmd = "hemlock role-create --name "+data['name']
return os.popen(cmd).read()
elif "schedule_server" in web.ctx['fullpath']:
cmd = "hemlock schedule-server-create --name "+data['name']
return os.popen(cmd).read()
elif "tenant" in web.ctx['fullpath']:
cmd = "hemlock tenant-create --name "+data['name']
return os.popen(cmd).read()
elif "schedule" in web.ctx['fullpath']:
cmd = "hemlock client-schedule --name "+data['name']+" --minute "+data['minute']+" --hour "+data['hour']+" --day_of_month "+data['day_of_month']+" --month "+data['month']+" --day_of_week "+data['day_of_week']+" --client_id "+data['client_id']
return os.popen(cmd).read()
elif "client" in web.ctx['fullpath']:
# !! TODO add no_coucnhase flag
cmd = "hemlock client-store --name "+data['name']+" --type "+data['type']+" --system_id "+data['system_id']+" --credential_file "+data['credential_file']
return os.popen(cmd).read()
elif "hemlock-server" in web.ctx['fullpath']:
cmd = "hemlock hemlock-server-store --credential_file "+data['credential_file']
return os.popen(cmd).read()
elif "user" in web.ctx['fullpath']:
cmd = "hemlock user-create --name "+data['name']+" --username "+data['username']+" --email "+data['email']+" --role_id "+data['role_id']+" --tenant_id "+data['tenant_id']
child = pexpect.spawn(cmd)
child.expect('Password:')
child.sendline(data['password'])
return child.read()
return
[docs]class delete:
"""
This class is responsible for all API actions that involve deleting
something.
"""
[docs] def GET(self, uuid):
"""
Performs the delete actions of the API.
:param uuid: the uuid of the item being deleted
:return: returns the result of the action
"""
if "role" in web.ctx['fullpath']:
cmd = "hemlock role-delete --uuid "+uuid
elif "schedule_server" in web.ctx['fullpath']:
cmd = "hemlock schedule-server-delete --uuid "+uuid
elif "system" in web.ctx['fullpath']:
cmd = "hemlock system-delete --uuid "+uuid
elif "user" in web.ctx['fullpath']:
cmd = "hemlock user-delete --uuid "+uuid
elif "tenant" in web.ctx['fullpath']:
cmd = "hemlock tenant-delete --uuid "+uuid
elif "schedule" in web.ctx['fullpath']:
cmd = "hemlock schedule-delete --uuid "+uuid
elif "client" in web.ctx['fullpath']:
cmd = "hemlock client-purge --uuid "+uuid
return os.popen(cmd).read()
[docs]class deregister:
"""
This class is responsible for deregistering systems.
"""
[docs] def GET(self, uuid):
"""
Performs the deregister action of the API.
:param uuid: the uuid of the system being deregistered
:return: returns the result of the action
"""
if "local" in web.ctx['fullpath']:
cmd = "hemlock deregister-local-system --uuid "+uuid
elif "remote" in web.ctx['fullpath']:
cmd = "hemlock deregister-remote-system --uuid "+uuid
return os.popen(cmd).read()
[docs]class get:
"""
This class is responsible for all API actions that involve getting
something.
"""
[docs] def GET(self, uuid):
"""
Performs the get actions of the API.
:param uuid: the uuid of the item to get
:return: returns the result of the action
"""
if "role" in web.ctx['fullpath']:
cmd = "hemlock role-get --uuid "+uuid
elif "schedule_server" in web.ctx['fullpath']:
cmd = "hemlock schedule-server-get --uuid "+uuid
elif "system" in web.ctx['fullpath']:
cmd = "hemlock system-get --uuid "+uuid
elif "tenant" in web.ctx['fullpath']:
cmd = "hemlock tenant-get --uuid "+uuid
elif "user" in web.ctx['fullpath']:
cmd = "hemlock user-get --uuid "+uuid
elif "client" in web.ctx['fullpath']:
cmd = "hemlock client-get --uuid "+uuid
elif "schedule" in web.ctx['fullpath']:
cmd = "hemlock schedule-get --uuid "+uuid
return os.popen(cmd).read()
[docs]class list1:
"""
This class is responsible for all API actions that involve listing
a type of something.
"""
[docs] def GET(self):
"""
Performs the list actions of the API for a given type.
:returns: returns the results of the action
"""
if "roles" in web.ctx['fullpath']:
cmd = "hemlock role-list"
elif "schedule_server" in web.ctx['fullpath']:
cmd = "hemlock schedule-server-list"
elif "systems" in web.ctx['fullpath']:
cmd = "hemlock system-list"
elif "tenants" in web.ctx['fullpath']:
cmd = "hemlock tenant-list"
elif "users" in web.ctx['fullpath']:
cmd = "hemlock user-list"
elif "clients" in web.ctx['fullpath']:
cmd = "hemlock client-list"
elif "schedules" in web.ctx['fullpath']:
cmd = "hemlock schedule-list"
elif "all" in web.ctx['fullpath']:
cmd = "hemlock list-all"
return os.popen(cmd).read()
[docs]class list2:
"""
This class is responsible for all API actions that involve listing
something specific to something else.
"""
[docs] def GET(self, uuid):
"""
Performs the list actions of the API specific to a given something.
:param uuid: the uuid of the specific item to get a list relative to
:return: returns the results of the action
"""
if "system" in web.ctx['fullpath'] and "tenants" in web.ctx['fullpath']:
cmd = "hemlock system-tenants-list --uuid "+uuid
elif "tenant" in web.ctx['fullpath'] and "systems" in web.ctx['fullpath']:
cmd = "hemlock tenant-systems-list --uuid "+uuid
elif "tenant" in web.ctx['fullpath'] and "users" in web.ctx['fullpath']:
cmd = "hemlock tenant-users-list --uuid "+uuid
elif "user" in web.ctx['fullpath'] and "roles" in web.ctx['fullpath']:
cmd = "hemlock user-roles-list --uuid "+uuid
elif "role" in web.ctx['fullpath'] and "users" in web.ctx['fullpath']:
cmd = "hemlock role-users-list --uuid "+uuid
elif "user" in web.ctx['fullpath'] and "tenants" in web.ctx['fullpath']:
cmd = "hemlock user-tenants-list --uuid "+uuid
elif "client" in web.ctx['fullpath'] and "schedules" in web.ctx['fullpath']:
cmd = "hemlock client-schedules-list --uuid "+uuid
elif "client" in web.ctx['fullpath'] and "systems" in web.ctx['fullpath']:
cmd = "hemlock client-systems-list --uuid "+uuid
elif "schedule" in web.ctx['fullpath'] and "clients" in web.ctx['fullpath']:
cmd = "hemlock schedule-clients-list --uuid "+uuid
elif "system" in web.ctx['fullpath'] and "clients" in web.ctx['fullpath']:
cmd = "hemlock system-clients-list --uuid "+uuid
return os.popen(cmd).read()
[docs]class register:
"""
This class is responsble for registering a system.
"""
[docs] def POST(self):
"""
Performs the register action of the API.
:return: returns the result of the action
"""
data = web.data()
data = ast.literal_eval(data)
if "local" in web.ctx['fullpath']:
cmd = "hemlock register-local-system --name "+data['name']+" --data_type "+data['data_type']+" --description "+data['description']+" --tenant_id "+data['tenant_id']+" --hostname "+data['hostname']+" --endpoint "+data['endpoint']+" --poc_name "+data['poc_name']+" --poc_email "+data['poc_email']
elif "remote" in web.ctx['fullpath']:
cmd = "hemlock register-remote-system --name "+data['name']+" --data_type "+data['data_type']+" --description "+data['description']+" --tenant_id "+data['tenant_id']+" --hostname "+data['hostname']+" --port "+data['port']+" --remote_uri "+data['remote_uri']+" --poc_name "+data['poc_name']+" --poc_email "+data['poc_email']
return os.popen(cmd).read()
[docs]class remove:
"""
This class is responsible for all API actions that involve removing
something.
"""
[docs] def GET(self, first, second):
"""
Performs the remove actions of the API.
:param first: the uuid of the first part of the action
:param second: the uuid of the second part of the action
:return: returns the result of the action
"""
if "role" in web.ctx['fullpath']:
cmd = "hemlock user-remove-role --uuid "+first+" --role_id "+second
if "system" in web.ctx['fullpath']:
cmd = "hemlock system-remove-tenant --uuid "+first+" --tenant_id "+second
elif "user" in web.ctx['fullpath']:
cmd = "hemlock user-remove-tenant --uuid "+first+" --tenant_id "+second
elif "remove/client" in web.ctx['fullpath']:
cmd = "hemlock client-remove-schedule --uuid "+first+" --schedule_id "+second
elif "remove/schedule" in web.ctx['fullpath']:
cmd = "hemlock schedule-remove-client --uuid "+first+" --client_id "+second
return os.popen(cmd).read()
[docs]class run:
"""
This class is responsible for performing a run action of the API.
"""
[docs] def GET(self, first, second):
# !! TODO add no_coucnhase flag
# !! TODO this needs to be updated and tested
"""
Performs the run action of the API.
:param first: the uuid of the client to run
:param second: the client type that is to run
:returns: returns the result of the action
"""
cmd = "hemlock client-run --uuid "+first+" --client "+second
return os.popen(cmd).read()
if __name__ == "__main__":
hemlock_rest = Hemlock_REST()
hemlock_rest.app.run()