2019-03-21 11:19:28 -04:00
#!/usr/bin/env python3
2019-07-05 14:11:01 -04:00
# api.py - PVC HTTP API interface
2019-03-21 11:19:28 -04:00
# Part of the Parallel Virtual Cluster (PVC) system
#
# Copyright (C) 2018 Joshua M. Boniface <joshua@boniface.me>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
###############################################################################
import flask
2019-04-12 16:59:26 -04:00
import json
2019-07-06 01:48:45 -04:00
import yaml
import os
2019-03-21 11:19:28 -04:00
2019-07-06 01:48:45 -04:00
import gevent . pywsgi
2019-07-05 13:20:06 -04:00
2019-07-06 01:48:45 -04:00
import api_lib . pvcapi as pvcapi
2019-03-21 11:19:28 -04:00
2019-07-05 14:11:01 -04:00
api = flask . Flask ( __name__ )
2019-07-06 01:48:45 -04:00
api . config [ ' DEBUG ' ] = True
# Parse the configuration file
try :
pvc_config_file = os . environ [ ' PVC_CONFIG_FILE ' ]
except :
print ( ' Error: The " PVC_CONFIG_FILE " environment variable must be set before starting pvc-api. ' )
exit ( 1 )
# Read in the config
try :
with open ( pvc_config_file , ' r ' ) as cfgfile :
o_config = yaml . load ( cfgfile )
except Exception as e :
print ( ' ERROR: Failed to parse configuration file: {} ' . format ( e ) )
exit ( 1 )
try :
# Create the config object
config = {
2019-07-06 02:35:37 -04:00
' coordinators ' : o_config [ ' pvc ' ] [ ' coordinators ' ] ,
2019-07-06 01:48:45 -04:00
' listen_address ' : o_config [ ' pvc ' ] [ ' api ' ] [ ' listen_address ' ] ,
' listen_port ' : int ( o_config [ ' pvc ' ] [ ' api ' ] [ ' listen_port ' ] ) ,
' authentication_key ' : o_config [ ' pvc ' ] [ ' api ' ] [ ' authentication ' ] [ ' key ' ]
}
# Set the config object in the pvcapi namespace
pvcapi . config = config
except Exception as e :
print ( ' ERROR: {} . ' . format ( e ) )
exit ( 1 )
def authenticator ( function ) :
def authenticate ( * args , * * kwargs ) :
request_values = flask . request . values
if config [ ' authentication_key ' ] :
if ' key ' in request_values :
if request_values [ ' key ' ] == config [ ' authentication_key ' ] :
return function ( * args , * * kwargs )
else :
return flask . jsonify ( { " message " : " Authentication required " } ) , 401
else :
return flask . jsonify ( { " message " : " Authentication required " } ) , 401
else :
return function ( * args , * * kwargs )
authenticate . __name__ = function . __name__
return authenticate
2019-03-21 11:19:28 -04:00
2019-07-05 14:11:01 -04:00
@api.route ( ' /api/v1 ' , methods = [ ' GET ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-03-21 11:19:28 -04:00
def api_root ( ) :
2019-07-06 01:48:45 -04:00
return flask . jsonify ( { " message " : " PVC API version 1 " } ) , 209
2019-03-21 11:19:28 -04:00
2019-07-05 01:19:39 -04:00
#
# Node endpoints
#
2019-07-05 14:11:01 -04:00
@api.route ( ' /api/v1/node ' , methods = [ ' GET ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-03-21 11:19:28 -04:00
def api_node ( ) :
"""
2019-07-05 18:24:14 -04:00
Return a list of nodes with limit LIMIT .
2019-03-21 11:19:28 -04:00
"""
2019-07-05 18:24:14 -04:00
# Get name limit
if ' limit ' in flask . request . values :
limit = flask . request . values [ ' limit ' ]
else :
limit = None
2019-07-05 13:20:06 -04:00
2019-07-05 18:24:14 -04:00
return pvcapi . node_list ( limit )
@api.route ( ' /api/v1/node/<node> ' , methods = [ ' GET ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 18:24:14 -04:00
def api_node_info ( node ) :
2019-07-05 14:11:01 -04:00
"""
2019-07-05 18:24:14 -04:00
Return information about node NODE .
2019-07-05 14:11:01 -04:00
"""
2019-07-05 18:24:14 -04:00
# Same as specifying /node?limit=NODE
return pvcapi . node_list ( node )
2019-03-21 11:19:28 -04:00
2019-07-05 18:24:14 -04:00
@api.route ( ' /api/v1/node/<node>/secondary ' , methods = [ ' POST ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 18:24:14 -04:00
def api_node_secondary ( node ) :
2019-03-21 11:19:28 -04:00
"""
Take NODE out of primary router mode .
"""
2019-07-05 14:11:01 -04:00
return pvcapi . node_secondary ( node )
2019-03-21 11:19:28 -04:00
2019-07-05 18:24:14 -04:00
@api.route ( ' /api/v1/node/<node>/primary ' , methods = [ ' POST ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 18:24:14 -04:00
def api_node_primary ( node ) :
2019-03-21 11:19:28 -04:00
"""
Set NODE to primary router mode .
"""
2019-07-05 14:11:01 -04:00
return pvcapi . node_primary ( node )
2019-03-21 11:19:28 -04:00
2019-07-05 18:24:14 -04:00
@api.route ( ' /api/v1/node/<node>/flush ' , methods = [ ' POST ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 18:24:14 -04:00
def api_node_flush ( node ) :
2019-04-12 16:59:26 -04:00
"""
Flush NODE of running VMs .
"""
2019-07-05 14:11:01 -04:00
return pvcapi . node_flush ( node )
2019-04-12 16:59:26 -04:00
2019-07-05 18:24:14 -04:00
@api.route ( ' /api/v1/node/<node>/unflush ' , methods = [ ' POST ' ] )
@api.route ( ' /api/v1/node/<node>/ready ' , methods = [ ' POST ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 18:24:14 -04:00
def api_node_ready ( node ) :
2019-04-12 16:59:26 -04:00
"""
Restore NODE to active service .
"""
2019-07-05 14:11:01 -04:00
return pvcapi . node_ready ( node )
2019-04-12 16:59:26 -04:00
2019-07-05 13:20:06 -04:00
#
# VM endpoints
#
2019-07-05 14:11:01 -04:00
@api.route ( ' /api/v1/vm ' , methods = [ ' GET ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 13:20:06 -04:00
def api_vm ( ) :
2019-07-04 12:56:17 -04:00
"""
2019-07-05 13:20:06 -04:00
Return a list of VMs with limit LIMIT .
2019-07-04 12:56:17 -04:00
"""
2019-07-05 13:20:06 -04:00
# Get node limit
if ' node ' in flask . request . values :
node = flask . request . values [ ' node ' ]
else :
node = None
# Get state limit
if ' state ' in flask . request . values :
state = flask . request . values [ ' state ' ]
else :
state = None
# Get name limit
2019-07-05 13:05:33 -04:00
if ' limit ' in flask . request . values :
limit = flask . request . values [ ' limit ' ]
2019-07-04 12:56:17 -04:00
else :
limit = None
2019-07-05 14:11:01 -04:00
return pvcapi . vm_list ( node , state , limit )
2019-04-12 16:59:26 -04:00
2019-07-05 18:24:14 -04:00
@api.route ( ' /api/v1/vm/<vm> ' , methods = [ ' GET ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 18:24:14 -04:00
def api_vm_info ( vm ) :
"""
Get information about a virtual machine named VM .
2019-07-05 01:19:39 -04:00
"""
2019-07-05 18:24:14 -04:00
# Same as specifying /vm?limit=VM
return pvcapi . vm_list ( None , None , vm , is_fuzzy = False )
# TODO: #22
#@api.route('/api/v1/vm/<vm>/add', methods=['POST'])
2019-07-06 01:48:45 -04:00
#@authenticator
2019-07-05 18:24:14 -04:00
#def api_vm_add(vm):
# """
# Add a virtual machine named VM.
# """
# return pvcapi.vm_add()
@api.route ( ' /api/v1/vm/<vm>/define ' , methods = [ ' POST ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 18:24:14 -04:00
def api_vm_define ( vm ) :
2019-07-05 01:19:39 -04:00
"""
2019-07-06 01:48:45 -04:00
Define a virtual machine named VM from Libvirt XML .
2019-07-05 18:24:14 -04:00
"""
2019-07-06 01:48:45 -04:00
# Get XML data
if ' xml ' in flask . request . values :
libvirt_xml = flask . request . values [ ' xml ' ]
else :
return flask . jsonify ( { " message " : " ERROR: A Libvirt XML document must be specified. " } ) , 520
2019-07-05 18:24:14 -04:00
# Get node name
if ' node ' in flask . request . values :
node = flask . request . values [ ' node ' ]
else :
node = None
# Get target selector
if ' selector ' in flask . request . values :
selector = flask . request . values [ ' selector ' ]
else :
selector = None
return pvcapi . vm_define ( vm , libvirt_xml , node , selector )
2019-07-05 01:19:39 -04:00
2019-07-05 18:24:14 -04:00
@api.route ( ' /api/v1/vm/<vm>/modify ' , methods = [ ' POST ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 18:24:14 -04:00
def api_vm_modify ( vm ) :
2019-07-05 01:19:39 -04:00
"""
2019-07-05 18:24:14 -04:00
Modify an existing virtual machine named VM from Libvirt XML .
2019-07-05 01:19:39 -04:00
"""
2019-07-05 18:24:14 -04:00
# Get XML from the POST body
libvirt_xml = flask . request . data
# Get node name
if ' flag_restart ' in flask . request . values :
flag_restart = flask . request . values [ ' flag_restart ' ]
else :
flag_restart = None
2019-07-05 01:19:39 -04:00
2019-07-05 18:24:14 -04:00
return pvcapi . vm_modify ( vm , flag_restart , libvirt_xml )
@api.route ( ' /api/v1/vm/<vm>/undefine ' , methods = [ ' POST ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 18:24:14 -04:00
def api_vm_undefine ( vm ) :
2019-07-05 01:19:39 -04:00
"""
2019-07-05 18:24:14 -04:00
Undefine a virtual machine named VM .
2019-07-05 01:19:39 -04:00
"""
2019-07-05 18:24:14 -04:00
return pvcapi . vm_undefine ( vm )
2019-07-05 01:19:39 -04:00
2019-07-05 18:24:14 -04:00
@api.route ( ' /api/v1/vm/<vm>/remove ' , methods = [ ' POST ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 18:24:14 -04:00
def api_vm_remove ( vm ) :
2019-07-05 01:19:39 -04:00
"""
2019-07-05 18:24:14 -04:00
Remove a virtual machine named VM including all disks .
2019-07-05 01:19:39 -04:00
"""
2019-07-05 18:24:14 -04:00
return pvcapi . vm_remove ( vm )
2019-07-05 01:19:39 -04:00
2019-07-05 18:24:14 -04:00
@api.route ( ' /api/v1/vm/<vm>/dump ' , methods = [ ' GET ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 18:24:14 -04:00
def api_vm_dump ( vm ) :
2019-07-05 01:19:39 -04:00
"""
2019-07-05 18:24:14 -04:00
Dump the Libvirt XML configuration of a virtual machine named VM .
2019-07-05 01:19:39 -04:00
"""
2019-07-05 18:24:14 -04:00
return pvcapi . vm_dump ( vm )
2019-07-05 01:19:39 -04:00
2019-07-05 18:24:14 -04:00
@api.route ( ' /api/v1/vm/<vm>/start ' , methods = [ ' POST ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 18:24:14 -04:00
def api_vm_start ( vm ) :
2019-07-05 01:19:39 -04:00
"""
2019-07-05 18:24:14 -04:00
Start a virtual machine named VM .
2019-07-05 01:19:39 -04:00
"""
2019-07-05 18:24:14 -04:00
return pvcapi . vm_start ( vm )
2019-07-05 01:19:39 -04:00
2019-07-05 18:24:14 -04:00
@api.route ( ' /api/v1/vm/<vm>/restart ' , methods = [ ' POST ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 18:24:14 -04:00
def api_vm_restart ( vm ) :
2019-07-05 01:19:39 -04:00
"""
2019-07-05 18:24:14 -04:00
Restart a virtual machine named VM .
2019-07-05 01:19:39 -04:00
"""
2019-07-05 18:24:14 -04:00
return pvcapi . vm_restart ( vm )
2019-07-05 01:19:39 -04:00
2019-07-05 18:24:14 -04:00
@api.route ( ' /api/v1/vm/<vm>/shutdown ' , methods = [ ' POST ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 18:24:14 -04:00
def api_vm_shutdown ( vm ) :
2019-07-05 01:19:39 -04:00
"""
2019-07-05 18:24:14 -04:00
Shutdown a virtual machine named VM .
2019-07-05 01:19:39 -04:00
"""
2019-07-05 18:24:14 -04:00
return pvcapi . vm_shutdown ( vm )
2019-07-05 01:19:39 -04:00
2019-07-05 18:24:14 -04:00
@api.route ( ' /api/v1/vm/<vm>/stop ' , methods = [ ' POST ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 18:24:14 -04:00
def api_vm_stop ( vm ) :
2019-07-05 01:19:39 -04:00
"""
2019-07-05 18:24:14 -04:00
Forcibly stop a virtual machine named VM .
2019-07-05 01:19:39 -04:00
"""
2019-07-05 18:24:14 -04:00
return pvcapi . vm_stop ( vm )
2019-07-05 01:19:39 -04:00
2019-07-05 18:24:14 -04:00
@api.route ( ' /api/v1/vm/<vm>/move ' , methods = [ ' POST ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 18:24:14 -04:00
def api_vm_move ( vm ) :
2019-07-05 01:19:39 -04:00
"""
2019-07-05 18:24:14 -04:00
Move a virtual machine named VM to another node .
2019-07-05 01:19:39 -04:00
"""
2019-07-05 18:24:14 -04:00
# Get node name
if ' node ' in flask . request . values :
node = flask . request . values [ ' node ' ]
else :
node = None
# Get target selector
if ' selector ' in flask . request . values :
selector = flask . request . values [ ' selector ' ]
else :
selector = None
2019-07-05 01:19:39 -04:00
2019-07-05 18:24:14 -04:00
return pvcapi . vm_move ( vm , node , selector )
@api.route ( ' /api/v1/vm/<vm>/migrate ' , methods = [ ' POST ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 18:24:14 -04:00
def api_vm_migrate ( vm ) :
2019-07-05 01:19:39 -04:00
"""
2019-07-05 18:24:14 -04:00
Temporarily migrate a virtual machine named VM to another node .
2019-07-05 01:19:39 -04:00
"""
2019-07-05 18:24:14 -04:00
# Get node name
if ' node ' in flask . request . values :
node = flask . request . values [ ' node ' ]
else :
node = None
# Get target selector
if ' selector ' in flask . request . values :
selector = flask . request . values [ ' selector ' ]
else :
selector = None
2019-07-05 01:19:39 -04:00
2019-07-05 18:24:14 -04:00
# Get target selector
if ' flag_force ' in flask . request . values :
flag_force = True
else :
flag_force = False
return pvcapi . vm_migrate ( vm , node , selector , flag_force )
@api.route ( ' /api/v1/vm/<vm>/unmigrate ' , methods = [ ' POST ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 18:24:14 -04:00
def api_vm_unmigrate ( vm ) :
2019-07-05 01:19:39 -04:00
"""
2019-07-05 18:24:14 -04:00
Unmigrate a migrated virtual machine named VM .
2019-07-05 01:19:39 -04:00
"""
2019-07-05 18:24:14 -04:00
return pvcapi . vm_move ( vm )
2019-07-05 01:19:39 -04:00
2019-07-05 13:20:06 -04:00
#
# Network endpoints
#
2019-07-05 14:11:01 -04:00
@api.route ( ' /api/v1/network ' , methods = [ ' GET ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 13:20:06 -04:00
def api_net ( ) :
2019-07-04 12:56:17 -04:00
"""
2019-07-05 18:24:14 -04:00
Return a list of virtual client networks with limit LIMIT .
2019-07-04 12:56:17 -04:00
"""
# Get name limit
2019-07-05 13:05:33 -04:00
if ' limit ' in flask . request . values :
limit = flask . request . values [ ' limit ' ]
2019-07-04 12:56:17 -04:00
else :
limit = None
2019-07-05 14:11:01 -04:00
return pvcapi . net_list ( limit )
2019-07-04 12:56:17 -04:00
2019-07-05 18:24:14 -04:00
@api.route ( ' /api/v1/network/<network> ' , methods = [ ' GET ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 18:24:14 -04:00
def api_net_info ( network ) :
2019-07-05 01:19:39 -04:00
"""
2019-07-05 18:24:14 -04:00
Get information about a virtual client network with description NETWORK .
"""
# Same as specifying /network?limit=NETWORK
return pvcapi . net_list ( network )
@api.route ( ' /api/v1/network/<network>/add ' , methods = [ ' POST ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 18:24:14 -04:00
def api_net_add ( network ) :
"""
Add a virtual client network with description NETWORK .
2019-07-05 01:19:39 -04:00
"""
2019-07-05 21:39:04 -04:00
# Get network VNI
if ' vni ' in flask . request . values :
vni = flask . request . values [ ' vni ' ]
else :
return flask . jsonify ( { " message " : " ERROR: A VNI must be specified for the virtual network. " } ) , 520
# Get network type
if ' nettype ' in flask . request . values :
nettype = flask . request . values [ ' nettype ' ]
if not ' managed ' in nettype and not ' bridged ' in nettype :
return flask . jsonify ( { " message " : " ERROR: A valid nettype must be specified: ' managed ' or ' bridged ' . " } ) , 520
else :
return flask . jsonify ( { " message " : " ERROR: A nettype must be specified for the virtual network. " } ) , 520
# Get network domain
if ' domain ' in flask . request . values :
domain = flask . request . values [ ' domain ' ]
else :
domain = None
# Get ipv4 network
if ' ip4_network ' in flask . request . values :
ip4_network = flask . request . values [ ' ip4_network ' ]
else :
ip4_network = None
# Get ipv4 gateway
if ' ip4_gateway ' in flask . request . values :
ip4_gateway = flask . request . values [ ' ip4_gateway ' ]
else :
ip4_gateway = None
# Get ipv6 network
if ' ip6_network ' in flask . request . values :
ip6_network = flask . request . values [ ' ip6_network ' ]
else :
ip6_network = None
# Get ipv6 gateway
if ' ip6_gateway ' in flask . request . values :
ip6_gateway = flask . request . values [ ' ip6_gateway ' ]
else :
ip6_gateway = None
# Get ipv4 DHCP flag
if ' flag_dhcp4 ' in flask . request . values :
dhcp4_flag = True
else :
dhcp4_flag = False
# Get ipv4 DHCP start
if ' dhcp4_start ' in flask . request . values :
dhcp4_start = flask . request . values [ ' dhcp4_start ' ]
else :
dhcp4_start = None
# Get ipv4 DHCP end
if ' dhcp4_end ' in flask . request . values :
dhcp4_end = flask . request . values [ ' dhcp4_end ' ]
else :
dhcp4_end = None
return pvcapi . net_add ( vni , network , nettype , domain ,
ip4_network , ip4_gateway , ip6_network , ip6_gateway ,
dhcp4_flag , dhcp4_start , dhcp4_end )
2019-07-05 01:19:39 -04:00
2019-07-05 18:24:14 -04:00
@api.route ( ' /api/v1/network/<network>/modify ' , methods = [ ' POST ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 18:24:14 -04:00
def api_net_modify ( network ) :
2019-07-05 01:19:39 -04:00
"""
2019-07-05 18:24:14 -04:00
Modify a virtual client network with description NETWORK .
2019-07-05 01:19:39 -04:00
"""
2019-07-05 21:39:04 -04:00
# Get network VNI
if ' vni ' in flask . request . values :
vni = flask . request . values [ ' vni ' ]
else :
vni = None
# Get network type
if ' nettype ' in flask . request . values :
nettype = flask . request . values [ ' nettype ' ]
else :
vni = None
# Get network domain
if ' domain ' in flask . request . values :
domain = flask . request . values [ ' domain ' ]
else :
domain = None
# Get ipv4 network
if ' ip4_network ' in flask . request . values :
ip4_network = flask . request . values [ ' ip4_network ' ]
else :
ip4_network = None
# Get ipv4 gateway
if ' ip4_gateway ' in flask . request . values :
ip4_gateway = flask . request . values [ ' ip4_gateway ' ]
else :
ip4_gateway = None
# Get ipv6 network
if ' ip6_network ' in flask . request . values :
ip6_network = flask . request . values [ ' ip6_network ' ]
else :
ip6_network = None
# Get ipv6 gateway
if ' ip6_gateway ' in flask . request . values :
ip6_gateway = flask . request . values [ ' ip6_gateway ' ]
else :
ip6_gateway = None
# Get ipv4 DHCP flag
if ' flag_dhcp4 ' in flask . request . values :
dhcp4_flag = True
else :
dhcp4_flag = False
# Get ipv4 DHCP start
if ' dhcp4_start ' in flask . request . values :
dhcp4_start = flask . request . values [ ' dhcp4_start ' ]
else :
dhcp4_start = None
# Get ipv4 DHCP end
if ' dhcp4_end ' in flask . request . values :
dhcp4_end = flask . request . values [ ' dhcp4_end ' ]
else :
dhcp4_end = None
return pvcapi . net_modify ( vni , network , nettype , domain ,
ip4_network , ip4_gateway , ip6_network , ip6_gateway ,
dhcp4_flag , dhcp4_start , dhcp4_end )
2019-07-05 01:19:39 -04:00
2019-07-05 18:24:14 -04:00
@api.route ( ' /api/v1/network/<network>/remove ' , methods = [ ' POST ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 18:24:14 -04:00
def api_net_remove ( network ) :
2019-07-05 01:19:39 -04:00
"""
2019-07-05 18:24:14 -04:00
Remove a virtual client network with description NETWORK .
2019-07-05 01:19:39 -04:00
"""
2019-07-05 21:39:04 -04:00
return pvcapi . net_remove ( network )
2019-07-05 01:19:39 -04:00
2019-07-05 18:24:14 -04:00
@api.route ( ' /api/v1/network/<network>/dhcp ' , methods = [ ' GET ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 18:24:14 -04:00
def api_net_dhcp ( network ) :
2019-07-05 01:19:39 -04:00
"""
2019-07-05 18:24:14 -04:00
Return a list of DHCP leases in virtual client network with description NETWORK with limit LIMIT .
2019-07-05 01:19:39 -04:00
"""
# Get name limit
2019-07-05 13:05:33 -04:00
if ' limit ' in flask . request . values :
limit = flask . request . values [ ' limit ' ]
2019-07-05 01:19:39 -04:00
else :
limit = None
2019-07-05 14:11:01 -04:00
# Get static-only flag
if ' flag_static ' in flask . request . values :
flag_static = True
2019-07-05 01:19:39 -04:00
else :
2019-07-05 14:11:01 -04:00
flag_static = False
2019-07-05 01:19:39 -04:00
2019-07-05 14:11:01 -04:00
return pvcapi . net_dhcp_list ( network , limit . flag_static )
2019-07-05 01:19:39 -04:00
2019-07-05 18:24:14 -04:00
@api.route ( ' /api/v1/network/<network>/dhcp/<lease> ' , methods = [ ' GET ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 18:24:14 -04:00
def api_net_dhcp_info ( network , lease ) :
"""
Get information about a DHCP lease for MAC address LEASE in virtual client network with description NETWORK .
"""
# Same as specifying /network?limit=NETWORK
return pvcapi . net_dhcp_list ( network , lease , False )
@api.route ( ' /api/v1/network/<network>/dhcp/<lease>/add ' , methods = [ ' POST ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 18:24:14 -04:00
def api_net_dhcp_add ( network , lease ) :
2019-07-05 01:19:39 -04:00
"""
2019-07-05 18:24:14 -04:00
Add a static DHCP lease for MAC address LEASE to virtual client network with description NETWORK .
2019-07-05 01:19:39 -04:00
"""
2019-07-05 21:39:04 -04:00
# Get lease ipaddress
if ' ipaddress ' in flask . request . values :
ipaddress = flask . request . values [ ' ipaddress ' ]
else :
return flask . jsonify ( { " message " : " ERROR: An IP address must be specified for the lease. " } ) , 520
# Get lease hostname
if ' hostname ' in flask . request . values :
hostname = flask . request . values [ ' hostname ' ]
else :
hostname = None
return pvcapi . net_dhcp_add ( network , ipaddress , lease , hostname )
2019-07-05 01:19:39 -04:00
2019-07-05 18:24:14 -04:00
@api.route ( ' /api/v1/network/<network>/dhcp/<lease>/remove ' , methods = [ ' POST ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 18:24:14 -04:00
def api_net_dhcp_remove ( network , lease ) :
2019-07-05 01:19:39 -04:00
"""
2019-07-05 18:24:14 -04:00
Remove a static DHCP lease for MAC address LEASE from virtual client network with description NETWORK .
2019-07-05 01:19:39 -04:00
"""
2019-07-05 21:39:04 -04:00
return pvcapi . net_dhcp_remove ( network , lease )
2019-07-05 01:19:39 -04:00
2019-07-05 18:24:14 -04:00
@api.route ( ' /api/v1/network/<network>/acl ' , methods = [ ' GET ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 18:24:14 -04:00
def api_net_acl ( network ) :
2019-07-05 01:19:39 -04:00
"""
Return a list of network ACLs in network NETWORK with limit LIMIT .
"""
# Get name limit
2019-07-05 13:05:33 -04:00
if ' limit ' in flask . request . values :
limit = flask . request . values [ ' limit ' ]
2019-07-05 01:19:39 -04:00
else :
limit = None
# Get direction limit
2019-07-05 13:05:33 -04:00
if ' direction ' in flask . request . values :
direction = flask . request . values [ ' direction ' ]
2019-07-05 21:39:04 -04:00
if not ' in ' in direction and not ' out ' in direction :
return flash . jsonify ( { " message " : " ERROR: Direction must be either ' in ' or ' out ' ; for both, do not specify a direction. " } ) , 510
2019-07-05 01:19:39 -04:00
else :
direction = None
2019-07-05 14:11:01 -04:00
return pvcapi . net_acl_list ( network , limit , direction )
2019-07-05 01:19:39 -04:00
2019-07-05 18:24:14 -04:00
@api.route ( ' /api/v1/network/<network>/acl/<acl> ' , methods = [ ' GET ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 18:24:14 -04:00
def api_net_acl_info ( network , acl ) :
2019-07-05 13:20:06 -04:00
"""
2019-07-05 18:24:14 -04:00
Get information about a network access control entry with description ACL in virtual client network with description NETWORK .
"""
# Same as specifying /network?limit=NETWORK
return pvcapi . net_acl_list ( network , acl , None )
@api.route ( ' /api/v1/network/<network>/acl/<acl>/add ' , methods = [ ' POST ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 18:24:14 -04:00
def api_net_acl_add ( network , acl ) :
"""
Add an access control list with description ACL to virtual client network with description NETWORK .
2019-07-05 13:20:06 -04:00
"""
2019-07-05 21:39:04 -04:00
# Get rule direction
if ' direction ' in flask . request . values :
direction = flask . request . values [ ' limit ' ]
if not ' in ' in direction and not ' out ' in direction :
return flask . jsonify ( { " message " : " ERROR: Direction must be either ' in ' or ' out ' . " } ) , 510
else :
return flask . jsonify ( { " message " : " ERROR: A direction must be specified for the ACL. " } ) , 510
# Get rule data
if ' rule ' in flask . request . values :
rule = flask . request . values [ ' rule ' ]
else :
return flask . jsonify ( { " message " : " ERROR: A valid NFT rule line must be specified for the ACL. " } ) , 510
# Get order value
if ' order ' in flask . request . values :
order = flask . request . values [ ' order ' ]
else :
order = None
return pvcapi . net_acl_add ( network , direction , acl , rule , order )
2019-07-05 13:20:06 -04:00
2019-07-05 18:24:14 -04:00
@api.route ( ' /api/v1/network/<network>/acl/<acl>/remove ' , methods = [ ' POST ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 18:24:14 -04:00
def api_net_acl_remove ( network , acl ) :
2019-07-05 13:20:06 -04:00
"""
2019-07-05 18:24:14 -04:00
Remove an access control list with description ACL from virtual client network with description NETWORK .
2019-07-05 13:20:06 -04:00
"""
2019-07-05 21:39:04 -04:00
# Get rule direction
if ' direction ' in flask . request . values :
direction = flask . request . values [ ' limit ' ]
if not ' in ' in direction and not ' out ' in direction :
return flask . jsonify ( { " message " : " ERROR: Direction must be either ' in ' or ' out ' . " } ) , 510
else :
return flask . jsonify ( { " message " : " ERROR: A direction must be specified for the ACL. " } ) , 510
return pvcapi . net_acl_remove ( network , direction , acl )
2019-07-05 13:20:06 -04:00
2019-07-05 01:19:39 -04:00
#
2019-03-21 11:19:28 -04:00
# Ceph endpoints
2019-07-05 01:19:39 -04:00
#
2019-07-05 14:11:01 -04:00
@api.route ( ' /api/v1/ceph ' , methods = [ ' GET ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 01:19:39 -04:00
def api_ceph ( ) :
"""
Get the current Ceph cluster status .
"""
2019-07-05 14:11:01 -04:00
return pvcapi . ceph_status ( )
2019-07-05 01:19:39 -04:00
2019-07-05 14:11:01 -04:00
@api.route ( ' /api/v1/ceph/osd ' , methods = [ ' GET ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 01:19:39 -04:00
def api_ceph_osd ( ) :
"""
2019-07-05 13:20:06 -04:00
Get the list of OSDs in the Ceph storage cluster .
2019-07-05 01:19:39 -04:00
"""
2019-07-05 13:20:06 -04:00
# Get name limit
if ' limit ' in flask . request . values :
limit = flask . request . values [ ' limit ' ]
else :
limit = None
2019-07-05 14:11:01 -04:00
return pvcapi . ceph_osd_list ( limit )
2019-07-05 01:19:39 -04:00
2019-07-05 18:24:14 -04:00
@api.route ( ' /api/v1/ceph/osd/set ' , methods = [ ' POST ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 18:24:14 -04:00
def api_ceph_osd_set ( ) :
2019-07-05 01:19:39 -04:00
"""
2019-07-05 22:14:45 -04:00
Set OSD option OPTION on the PVC Ceph storage cluster , e . g . ' noout ' or ' noscrub ' .
2019-07-05 01:19:39 -04:00
"""
2019-07-05 22:14:45 -04:00
# Get OSD option
if ' option ' in flask . request . options :
option = flask . request . options [ ' option ' ]
else :
return flask . jsonify ( { " message " : " ERROR: An OSD option must be specified. " } ) , 510
return pvcapi . ceph_osd_set ( option )
2019-07-05 01:19:39 -04:00
2019-07-05 18:24:14 -04:00
@api.route ( ' /api/v1/ceph/osd/unset ' , methods = [ ' POST ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 18:24:14 -04:00
def api_ceph_osd_unset ( ) :
2019-07-05 01:19:39 -04:00
"""
2019-07-05 22:14:45 -04:00
Unset OSD option OPTION on the PVC Ceph storage cluster , e . g . ' noout ' or ' noscrub ' .
2019-07-05 01:19:39 -04:00
"""
2019-07-05 22:14:45 -04:00
# Get OSD option
if ' option ' in flask . request . options :
option = flask . request . options [ ' option ' ]
else :
return flask . jsonify ( { " message " : " ERROR: An OSD option must be specified. " } ) , 510
return pvcapi . ceph_osd_unset ( option )
2019-07-05 01:19:39 -04:00
2019-07-05 18:24:14 -04:00
@api.route ( ' /api/v1/ceph/osd/<osd> ' , methods = [ ' GET ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 18:24:14 -04:00
def api_ceph_osd_info ( osd ) :
2019-07-05 01:19:39 -04:00
"""
2019-07-05 18:24:14 -04:00
Get information about an OSD with ID OSD .
2019-07-05 01:19:39 -04:00
"""
2019-07-05 18:24:14 -04:00
# Same as specifying /osd?limit=OSD
return pvcapi . ceph_osd_list ( osd )
2019-07-05 01:19:39 -04:00
2019-07-05 22:14:45 -04:00
@api.route ( ' /api/v1/ceph/osd/<node>/add ' , methods = [ ' POST ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 22:14:45 -04:00
def api_ceph_osd_add ( node ) :
2019-07-05 01:19:39 -04:00
"""
2019-07-05 22:14:45 -04:00
Add a Ceph OSD to node NODE .
2019-07-05 01:19:39 -04:00
"""
2019-07-05 22:14:45 -04:00
# Get OSD device
if ' device ' in flask . request . devices :
device = flask . request . devices [ ' device ' ]
else :
return flask . jsonify ( { " message " : " ERROR: A block device must be specified. " } ) , 510
# Get OSD weight
if ' weight ' in flask . request . weights :
weight = flask . request . weights [ ' weight ' ]
else :
return flask . jsonify ( { " message " : " ERROR: An OSD weight must be specified. " } ) , 510
return pvcapi . ceph_osd_add ( node , device , weight )
2019-07-05 01:19:39 -04:00
2019-07-05 18:24:14 -04:00
@api.route ( ' /api/v1/ceph/osd/<osd>/remove ' , methods = [ ' POST ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 18:24:14 -04:00
def api_ceph_osd_remove ( osd ) :
2019-07-05 01:19:39 -04:00
"""
2019-07-05 18:24:14 -04:00
Remove a Ceph OSD with ID OSD .
2019-07-05 01:19:39 -04:00
"""
2019-07-05 22:14:45 -04:00
# Verify yes-i-really-mean-it flag
if not ' flag_yes_i_really_mean_it ' in flask . request . values :
return flask . jsonify ( { " message " : " ERROR: This command can have unintended consequences and should not be automated; if you ' re sure you know what you ' re doing, resend with the argument ' flag_yes_i_really_mean_it ' . " } ) , 599
return pvcapi . ceph_osd_remove ( osd )
2019-07-05 01:19:39 -04:00
2019-07-05 18:24:14 -04:00
@api.route ( ' /api/v1/ceph/osd/<osd>/in ' , methods = [ ' POST ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 18:24:14 -04:00
def api_ceph_osd_in ( osd ) :
2019-07-05 01:19:39 -04:00
"""
2019-07-05 18:24:14 -04:00
Set in a Ceph OSD with ID OSD .
2019-07-05 01:19:39 -04:00
"""
2019-07-05 22:14:45 -04:00
return pvcapi . ceph_osd_in ( osd )
2019-07-05 18:24:14 -04:00
@api.route ( ' /api/v1/ceph/osd/<osd>/out ' , methods = [ ' POST ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 18:24:14 -04:00
def api_ceph_osd_out ( osd ) :
"""
Set out a Ceph OSD with ID OSD .
"""
2019-07-05 22:14:45 -04:00
return pvcapi . ceph_osd_out ( osd )
2019-03-21 11:19:28 -04:00
2019-07-05 14:11:01 -04:00
@api.route ( ' /api/v1/ceph/pool ' , methods = [ ' GET ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 13:20:06 -04:00
def api_ceph_pool ( ) :
2019-07-05 01:19:39 -04:00
"""
2019-07-05 13:20:06 -04:00
Get the list of RBD pools in the Ceph storage cluster .
2019-07-05 01:19:39 -04:00
"""
# Get name limit
2019-07-05 13:05:33 -04:00
if ' limit ' in flask . request . values :
limit = flask . request . values [ ' limit ' ]
2019-07-05 01:19:39 -04:00
else :
limit = None
2019-07-05 14:11:01 -04:00
return pvcapi . ceph_pool_list ( limit )
2019-07-05 01:19:39 -04:00
2019-07-05 18:24:14 -04:00
@api.route ( ' /api/v1/ceph/pool/<pool> ' , methods = [ ' GET ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 18:24:14 -04:00
def api_ceph_pool_info ( pool ) :
2019-07-05 01:19:39 -04:00
"""
2019-07-05 18:24:14 -04:00
Get information about an RBD pool with name POOL .
"""
# Same as specifying /pool?limit=POOL
return pvcapi . ceph_pool_list ( pool )
@api.route ( ' /api/v1/ceph/pool/<pool>/add ' , methods = [ ' POST ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 18:24:14 -04:00
def api_ceph_pool_add ( pool ) :
"""
Add a Ceph RBD pool with name POOL .
2019-07-05 01:19:39 -04:00
"""
2019-07-05 22:14:45 -04:00
# Get placement groups
if ' pgs ' in flask . request . values :
pgs = flask . request . values [ ' pgs ' ]
else :
# We default to a very small number; DOCUMENT THIS
pgs = 128
return pvcapi . ceph_pool_add ( pool , pgs )
2019-07-05 01:19:39 -04:00
2019-07-05 18:24:14 -04:00
@api.route ( ' /api/v1/ceph/pool/<pool>/remove ' , methods = [ ' POST ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 18:24:14 -04:00
def api_ceph_pool_remove ( pool ) :
2019-07-05 01:19:39 -04:00
"""
2019-07-05 18:24:14 -04:00
Remove a Ceph RBD pool with name POOL .
2019-07-05 01:19:39 -04:00
"""
2019-07-05 22:14:45 -04:00
# Verify yes-i-really-mean-it flag
if not ' flag_yes_i_really_mean_it ' in flask . request . values :
return flask . jsonify ( { " message " : " ERROR: This command can have unintended consequences and should not be automated; if you ' re sure you know what you ' re doing, resend with the argument ' flag_yes_i_really_mean_it ' . " } ) , 599
return pvcapi . ceph_pool_remove ( pool )
2019-07-05 01:19:39 -04:00
2019-07-05 14:11:01 -04:00
@api.route ( ' /api/v1/ceph/volume ' , methods = [ ' GET ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 13:20:06 -04:00
def api_ceph_volume ( ) :
2019-07-05 01:19:39 -04:00
"""
2019-07-05 13:20:06 -04:00
Get the list of RBD volumes in the Ceph storage cluster .
2019-07-05 01:19:39 -04:00
"""
2019-07-05 13:20:06 -04:00
# Get pool limit
if ' pool ' in flask . request . values :
pool = flask . request . values [ ' pool ' ]
else :
2019-07-05 14:11:01 -04:00
pool = None
2019-07-05 01:19:39 -04:00
2019-07-05 18:24:14 -04:00
# Get name limit
if ' limit ' in flask . request . values :
limit = flask . request . values [ ' limit ' ]
else :
limit = None
2019-07-05 14:11:01 -04:00
return pvcapi . ceph_volume_list ( pool , limit )
2019-07-05 01:19:39 -04:00
2019-07-05 18:24:14 -04:00
@api.route ( ' /api/v1/ceph/volume/<pool>/<volume> ' , methods = [ ' GET ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 18:24:14 -04:00
def api_ceph_volume_info ( pool , volume ) :
"""
Get information about an RBD volume with name VOLUME in RBD pool with name POOL .
"""
# Same as specifying /volume?limit=VOLUME
return pvcapi . ceph_osd_list ( pool , osd )
@api.route ( ' /api/v1/ceph/volume/<pool>/<volume>/add ' , methods = [ ' POST ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 18:24:14 -04:00
def api_ceph_volume_add ( pool , volume ) :
2019-07-05 01:19:39 -04:00
"""
2019-07-05 18:24:14 -04:00
Add a Ceph RBD volume with name VOLUME to RBD pool with name POOL .
2019-07-05 01:19:39 -04:00
"""
2019-07-05 22:14:45 -04:00
# Get volume size
if ' size ' in flask . request . values :
size = flask . request . values [ ' size ' ]
else :
return flask . jsonify ( { " message " : " ERROR: A volume size in bytes (or with an M/G/T suffix) must be specified. " } ) , 510
return pvcapi . ceph_volume_add ( pool , volume , size )
2019-07-05 01:19:39 -04:00
2019-07-05 18:24:14 -04:00
@api.route ( ' /api/v1/ceph/volume/<pool>/<volume>/remove ' , methods = [ ' POST ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 18:24:14 -04:00
def api_ceph_volume_remove ( pool , volume ) :
2019-07-05 01:19:39 -04:00
"""
2019-07-05 18:24:14 -04:00
Remove a Ceph RBD volume with name VOLUME from RBD pool with name POOL .
2019-07-05 01:19:39 -04:00
"""
2019-07-05 22:14:45 -04:00
return pvcapi . ceph_volume_remove ( pool , volume )
2019-07-05 01:19:39 -04:00
2019-07-05 14:11:01 -04:00
@api.route ( ' /api/v1/ceph/volume/snapshot ' , methods = [ ' GET ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 13:20:06 -04:00
def api_ceph_volume_snapshot ( ) :
2019-07-05 01:19:39 -04:00
"""
2019-07-05 13:20:06 -04:00
Get the list of RBD volume snapshots in the Ceph storage cluster .
2019-07-05 01:19:39 -04:00
"""
2019-07-05 14:11:01 -04:00
# Get pool limit
if ' pool ' in flask . request . values :
pool = flask . request . values [ ' pool ' ]
2019-07-05 01:19:39 -04:00
else :
2019-07-05 14:11:01 -04:00
pool = None
2019-07-05 01:19:39 -04:00
2019-07-05 13:20:06 -04:00
# Get volume limit
if ' volume ' in flask . request . values :
volume = flask . request . values [ ' volume ' ]
else :
2019-07-05 14:11:01 -04:00
volume = None
2019-07-05 13:20:06 -04:00
2019-07-05 14:11:01 -04:00
# Get name limit
if ' limit ' in flask . request . values :
limit = flask . request . values [ ' limit ' ]
2019-07-05 01:19:39 -04:00
else :
2019-07-05 14:11:01 -04:00
limit = None
2019-07-05 01:19:39 -04:00
2019-07-05 14:11:01 -04:00
return pvcapi . ceph_volume_snapshot_list ( pool , volume , limit )
2019-07-05 01:19:39 -04:00
2019-07-05 18:24:14 -04:00
@api.route ( ' /api/v1/ceph/volume/snapshot/<pool>/<volume>/<snapshot> ' , methods = [ ' GET ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 18:24:14 -04:00
def api_ceph_volume_snapshot_info ( pool , volume , snapshot ) :
"""
Get information about a snapshot with name SNAPSHOT of RBD volume with name VOLUME in RBD pool with name POOL .
"""
# Same as specifying /snapshot?limit=VOLUME
return pvcapi . ceph_snapshot_list ( pool , volume , snapshot )
@api.route ( ' /api/v1/ceph/volume/snapshot/<pool>/<volume>/<snapshot>/add ' , methods = [ ' POST ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 18:24:14 -04:00
def api_ceph_volume_snapshot_add ( pool , volume , snapshot ) :
2019-07-05 01:19:39 -04:00
"""
2019-07-05 18:24:14 -04:00
Add a Ceph RBD volume snapshot with name SNAPSHOT of RBD volume with name VOLUME in RBD pool with name POOL .
2019-07-05 01:19:39 -04:00
"""
2019-07-05 22:14:45 -04:00
return pvcapi . ceph_volume_snapshot_add ( pool , volume , snapshot )
2019-07-05 01:19:39 -04:00
2019-07-05 18:24:14 -04:00
@api.route ( ' /api/v1/ceph/volume/snapshot/<pool>/<volume>/<snapshot>/remove ' , methods = [ ' POST ' ] )
2019-07-06 01:48:45 -04:00
@authenticator
2019-07-05 18:24:14 -04:00
def api_ceph_volume_snapshot_remove ( pool , volume , snapshot ) :
2019-07-05 01:19:39 -04:00
"""
2019-07-05 18:24:14 -04:00
Remove a Ceph RBD volume snapshot with name SNAPSHOT from RBD volume with name VOLUME in RBD pool with name POOL .
2019-07-05 01:19:39 -04:00
"""
2019-07-05 22:14:45 -04:00
return pvcapi . ceph_volume_snapshot_remove ( pool , volume , snapshot )
2019-07-05 01:19:39 -04:00
#
# Entrypoint
#
2019-07-06 01:48:45 -04:00
http_server = gevent . pywsgi . WSGIServer ( ( config [ ' listen_address ' ] , config [ ' listen_port ' ] ) , api )
http_server . serve_forever ( )