2018-05-31 20:26:44 -04:00
#!/usr/bin/env python3
2019-03-20 12:06:15 -04:00
# pvc.py - PVC client command-line interface
2018-06-06 01:47:53 -04:00
# Part of the Parallel Virtual Cluster (PVC) system
#
2019-10-13 12:09:51 -04:00
# Copyright (C) 2018-2019 Joshua M. Boniface <joshua@boniface.me>
2018-06-06 01:47:53 -04:00
#
# 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/>.
#
###############################################################################
2018-06-14 12:07:46 -04:00
import socket
import click
2018-09-25 02:32:08 -04:00
import tempfile
import os
import subprocess
import difflib
import re
import colorama
2019-03-12 22:55:29 -04:00
import yaml
2018-06-14 12:07:46 -04:00
2019-05-10 23:25:06 -04:00
import client_lib . ansiprint as ansiprint
2018-09-21 23:43:30 -04:00
import client_lib . common as pvc_common
2019-10-22 11:23:12 -04:00
import client_lib . cluster as pvc_cluster
2018-09-21 23:43:30 -04:00
import client_lib . node as pvc_node
import client_lib . vm as pvc_vm
import client_lib . network as pvc_network
2018-10-27 18:11:58 -04:00
import client_lib . ceph as pvc_ceph
2019-03-17 12:56:52 -04:00
#import client_lib.provisioner as pvc_provisioner
2018-06-05 01:39:59 -04:00
2019-05-23 22:27:34 -04:00
myhostname = socket . gethostname ( ) . split ( ' . ' ) [ 0 ]
2018-06-14 11:57:36 -04:00
zk_host = ' '
2018-06-11 01:35:50 -04:00
CONTEXT_SETTINGS = dict ( help_option_names = [ ' -h ' , ' --help ' ] , max_content_width = 120 )
2019-04-09 16:25:45 -04:00
def cleanup ( retcode , retmsg , zk_conn = None ) :
if zk_conn :
pvc_common . stopZKConnection ( zk_conn )
2018-09-20 03:25:58 -04:00
if retcode == True :
if retmsg != ' ' :
click . echo ( retmsg )
exit ( 0 )
else :
if retmsg != ' ' :
click . echo ( retmsg )
exit ( 1 )
2018-06-05 01:39:59 -04:00
###############################################################################
# pvc node
###############################################################################
2018-10-14 02:01:35 -04:00
@click.group ( name = ' node ' , short_help = ' Manage a PVC node. ' , context_settings = CONTEXT_SETTINGS )
2018-09-20 03:25:58 -04:00
def cli_node ( ) :
2018-06-05 01:39:59 -04:00
"""
Manage the state of a node in the PVC cluster .
"""
pass
2018-10-14 02:01:35 -04:00
###############################################################################
# pvc node secondary
###############################################################################
@click.command ( name = ' secondary ' , short_help = ' Set a node in secondary node status. ' )
@click.argument (
' node '
)
def node_secondary ( node ) :
"""
Take NODE out of primary router mode .
"""
zk_conn = pvc_common . startZKConnection ( zk_host )
retcode , retmsg = pvc_node . secondary_node ( zk_conn , node )
cleanup ( retcode , retmsg , zk_conn )
###############################################################################
# pvc node primary
###############################################################################
@click.command ( name = ' primary ' , short_help = ' Set a node in primary status. ' )
@click.argument (
' node '
)
def node_primary ( node ) :
"""
Put NODE into primary router mode .
"""
zk_conn = pvc_common . startZKConnection ( zk_host )
retcode , retmsg = pvc_node . primary_node ( zk_conn , node )
cleanup ( retcode , retmsg , zk_conn )
2018-06-05 01:39:59 -04:00
###############################################################################
# pvc node flush
###############################################################################
2018-07-18 22:28:49 -04:00
@click.command ( name = ' flush ' , short_help = ' Take a node out of service. ' )
2018-07-17 01:48:15 -04:00
@click.option (
' -w ' , ' --wait ' , ' wait ' , is_flag = True , default = False ,
help = ' Wait for migrations to complete before returning. '
)
2018-06-16 22:22:07 -04:00
@click.argument (
' node ' , default = myhostname
2018-06-06 20:49:07 -04:00
)
2018-09-20 03:25:58 -04:00
def node_flush ( node , wait ) :
2018-06-05 01:39:59 -04:00
"""
2018-06-16 22:22:07 -04:00
Take NODE out of active service and migrate away all VMs . If unspecified , defaults to this host .
2018-06-05 01:39:59 -04:00
"""
2018-09-20 03:25:58 -04:00
2018-09-21 23:43:30 -04:00
zk_conn = pvc_common . startZKConnection ( zk_host )
2018-09-23 01:05:54 -04:00
retcode , retmsg = pvc_node . flush_node ( zk_conn , node , wait )
cleanup ( retcode , retmsg , zk_conn )
2018-06-05 01:39:59 -04:00
###############################################################################
2018-06-26 23:46:03 -04:00
# pvc node ready/unflush
2018-06-05 01:39:59 -04:00
###############################################################################
2018-07-18 22:28:49 -04:00
@click.command ( name = ' ready ' , short_help = ' Restore node to service. ' )
2018-06-16 22:22:07 -04:00
@click.argument (
' node ' , default = myhostname
2018-06-06 20:49:07 -04:00
)
2019-05-11 00:16:38 -04:00
@click.option (
' -w ' , ' --wait ' , ' wait ' , is_flag = True , default = False ,
help = ' Wait for migrations to complete before returning. '
)
def node_ready ( node , wait ) :
2018-07-18 22:58:41 -04:00
"""
Restore NODE to active service and migrate back all VMs . If unspecified , defaults to this host .
"""
2018-09-21 23:43:30 -04:00
zk_conn = pvc_common . startZKConnection ( zk_host )
2019-05-11 00:16:38 -04:00
retcode , retmsg = pvc_node . ready_node ( zk_conn , node , wait )
2018-09-23 01:05:54 -04:00
cleanup ( retcode , retmsg , zk_conn )
2018-06-26 23:46:03 -04:00
2018-07-18 22:28:49 -04:00
@click.command ( name = ' unflush ' , short_help = ' Restore node to service. ' )
2018-06-26 23:46:03 -04:00
@click.argument (
' node ' , default = myhostname
)
2019-05-11 00:16:38 -04:00
@click.option (
' -w ' , ' --wait ' , ' wait ' , is_flag = True , default = False ,
help = ' Wait for migrations to complete before returning. '
)
def node_unflush ( node , wait ) :
2018-07-18 22:58:41 -04:00
"""
Restore NODE to active service and migrate back all VMs . If unspecified , defaults to this host .
"""
2018-09-21 23:43:30 -04:00
zk_conn = pvc_common . startZKConnection ( zk_host )
2019-05-11 00:16:38 -04:00
retcode , retmsg = pvc_node . ready_node ( zk_conn , node , wait )
2018-09-23 01:05:54 -04:00
cleanup ( retcode , retmsg , zk_conn )
2018-06-05 01:39:59 -04:00
2018-06-11 02:49:47 -04:00
###############################################################################
# pvc node info
###############################################################################
2018-07-18 22:28:49 -04:00
@click.command ( name = ' info ' , short_help = ' Show details of a node object. ' )
2018-06-16 22:22:07 -04:00
@click.argument (
' node ' , default = myhostname
2018-06-11 02:49:47 -04:00
)
@click.option (
' -l ' , ' --long ' , ' long_output ' , is_flag = True , default = False ,
help = ' Display more detailed information. '
)
2018-06-16 22:22:07 -04:00
def node_info ( node , long_output ) :
2018-06-11 02:49:47 -04:00
"""
2018-06-16 22:22:07 -04:00
Show information about node NODE . If unspecified , defaults to this host .
2018-06-11 02:49:47 -04:00
"""
2018-09-21 23:43:30 -04:00
zk_conn = pvc_common . startZKConnection ( zk_host )
2019-05-10 23:25:06 -04:00
retcode , retdata = pvc_node . get_info ( zk_conn , node )
if retcode :
2019-05-20 22:15:28 -04:00
pvc_node . format_info ( retdata , long_output )
2019-05-10 23:25:06 -04:00
if long_output :
click . echo ( ' {} Virtual machines on node: {} ' . format ( ansiprint . bold ( ) , ansiprint . end ( ) ) )
click . echo ( ' ' )
pvc_vm . get_list ( zk_conn , node , None , None , None )
click . echo ( ' ' )
retdata = ' '
cleanup ( retcode , retdata , zk_conn )
2018-06-11 02:49:47 -04:00
###############################################################################
# pvc node list
###############################################################################
2018-07-18 22:28:49 -04:00
@click.command ( name = ' list ' , short_help = ' List all node objects. ' )
2018-07-19 21:58:11 -04:00
@click.argument (
' limit ' , default = None , required = False
)
def node_list ( limit ) :
2018-06-11 02:49:47 -04:00
"""
2018-10-14 02:01:35 -04:00
List all nodes in the cluster ; optionally only match names matching regex LIMIT .
2018-06-11 02:49:47 -04:00
"""
2018-09-21 23:43:30 -04:00
zk_conn = pvc_common . startZKConnection ( zk_host )
2019-05-10 23:25:06 -04:00
retcode , retdata = pvc_node . get_list ( zk_conn , limit )
if retcode :
pvc_node . format_list ( retdata )
retdata = ' '
cleanup ( retcode , retdata , zk_conn )
2018-06-11 02:49:47 -04:00
2018-06-05 01:39:59 -04:00
###############################################################################
# pvc vm
###############################################################################
2018-07-18 22:30:23 -04:00
@click.group ( name = ' vm ' , short_help = ' Manage a PVC virtual machine. ' , context_settings = CONTEXT_SETTINGS )
2018-09-20 03:25:58 -04:00
def cli_vm ( ) :
2018-06-05 01:39:59 -04:00
"""
Manage the state of a virtual machine in the PVC cluster .
"""
pass
###############################################################################
# pvc vm define
###############################################################################
@click.command ( name = ' define ' , short_help = ' Define a new virtual machine from a Libvirt XML file. ' )
@click.option (
2019-03-12 23:17:31 -04:00
' -t ' , ' --target ' , ' target_node ' ,
2019-10-12 01:17:39 -04:00
help = ' Home node for this domain; autoselect if unspecified. '
2018-07-18 12:15:39 -04:00
)
@click.option (
2019-10-12 01:17:39 -04:00
' -l ' , ' --limit ' , ' node_limit ' , default = None , show_default = False ,
help = ' Comma-separated list of nodes to limit VM operation to; saved with VM. '
)
@click.option (
' -s ' , ' --selector ' , ' node_selector ' , default = ' mem ' , show_default = True ,
2018-07-18 12:15:39 -04:00
type = click . Choice ( [ ' mem ' , ' load ' , ' vcpus ' , ' vms ' ] ) ,
2019-10-12 01:17:39 -04:00
help = ' Method to determine optimal target node during autoselect; saved with VM. '
)
@click.option (
2019-10-12 01:36:50 -04:00
' -a/-A ' , ' --autostart/--no-autostart ' , ' node_autostart ' , is_flag = True , default = False ,
2019-10-12 01:17:39 -04:00
help = ' Start VM automatically on next unflush/ready state of home node; unset by daemon once used. '
2018-06-05 01:39:59 -04:00
)
2018-06-16 22:22:07 -04:00
@click.argument (
' config ' , type = click . File ( )
)
2019-10-12 01:17:39 -04:00
def vm_define ( config , target_node , node_limit , node_selector , node_autostart ) :
2018-06-05 01:39:59 -04:00
"""
2018-06-16 22:22:07 -04:00
Define a new virtual machine from Libvirt XML configuration file CONFIG .
2018-06-05 01:39:59 -04:00
"""
2018-06-06 12:00:52 -04:00
# Open the XML file
2018-09-20 03:25:58 -04:00
config_data = config . read ( )
2018-06-16 22:22:07 -04:00
config . close ( )
2018-06-06 12:00:52 -04:00
2018-09-21 23:43:30 -04:00
zk_conn = pvc_common . startZKConnection ( zk_host )
2019-10-12 01:17:39 -04:00
retcode , retmsg = pvc_vm . define_vm ( zk_conn , config_data , target_node , node_limit , node_selector , node_autostart )
cleanup ( retcode , retmsg , zk_conn )
###############################################################################
# pvc vm meta
###############################################################################
@click.command ( name = ' meta ' , short_help = ' Modify PVC metadata of an existing VM. ' )
@click.option (
' -l ' , ' --limit ' , ' node_limit ' , default = None , show_default = False ,
2019-10-12 02:08:52 -04:00
help = ' Comma-separated list of nodes to limit VM operation to; set to an empty string to remove. '
2019-10-12 01:17:39 -04:00
)
@click.option (
' -s ' , ' --selector ' , ' node_selector ' , default = None , show_default = False ,
type = click . Choice ( [ ' mem ' , ' load ' , ' vcpus ' , ' vms ' ] ) ,
2019-10-12 02:08:52 -04:00
help = ' Method to determine optimal target node during autoselect. '
2019-10-12 01:17:39 -04:00
)
@click.option (
2019-10-12 01:36:50 -04:00
' -a/-A ' , ' --autostart/--no-autostart ' , ' node_autostart ' , is_flag = True , default = None ,
2019-10-12 01:17:39 -04:00
help = ' Start VM automatically on next unflush/ready state of home node; unset by daemon once used. '
)
@click.argument (
' domain '
)
def vm_meta ( domain , node_limit , node_selector , node_autostart ) :
"""
Modify the PVC metadata of existing virtual machine DOMAIN . At least one option to update must be specified . DOMAIN may be a UUID or name .
"""
if node_limit is None and node_selector is None and node_autostart is None :
cleanup ( False , ' At least one metadata option must be specified to update. ' )
zk_conn = pvc_common . startZKConnection ( zk_host )
retcode , retmsg = pvc_vm . modify_vm_metadata ( zk_conn , domain , node_limit , node_selector , node_autostart )
2018-09-20 03:25:58 -04:00
cleanup ( retcode , retmsg , zk_conn )
2018-06-06 12:00:52 -04:00
2018-07-20 00:38:31 -04:00
###############################################################################
# pvc vm modify
###############################################################################
@click.command ( name = ' modify ' , short_help = ' Modify an existing VM configuration. ' )
@click.option (
' -e ' , ' --editor ' , ' editor ' , is_flag = True ,
help = ' Use local editor to modify existing config. '
)
@click.option (
' -r ' , ' --restart ' , ' restart ' , is_flag = True ,
help = ' Immediately restart VM to apply new config. '
)
@click.argument (
' domain '
)
@click.argument (
' config ' , type = click . File ( ) , default = None , required = False
)
2018-09-20 03:25:58 -04:00
def vm_modify ( domain , config , editor , restart ) :
2018-07-20 00:38:31 -04:00
"""
Modify existing virtual machine DOMAIN , either in - editor or with replacement CONFIG . DOMAIN may be a UUID or name .
"""
if editor == False and config == None :
2018-09-20 03:25:58 -04:00
cleanup ( False , ' Either an XML config file or the " --editor " option must be specified. ' )
2018-07-20 00:38:31 -04:00
2018-09-21 23:43:30 -04:00
zk_conn = pvc_common . startZKConnection ( zk_host )
2018-07-20 00:38:31 -04:00
2019-04-10 16:18:18 -04:00
dom_uuid = pvc_vm . getDomainUUID ( zk_conn , domain )
if dom_uuid == None :
cleanup ( False , ' ERROR: Could not find VM " {} " in the cluster! ' . format ( domain ) )
dom_name = pvc_vm . getDomainName ( zk_conn , dom_uuid )
2018-09-20 03:25:58 -04:00
2019-04-10 16:18:18 -04:00
if editor == True :
2018-07-20 00:38:31 -04:00
# Grab the current config
current_vm_config = zk_conn . get ( ' /domains/ {} /xml ' . format ( dom_uuid ) ) [ 0 ] . decode ( ' ascii ' )
# Write it to a tempfile
fd , path = tempfile . mkstemp ( )
fw = os . fdopen ( fd , ' w ' )
fw . write ( current_vm_config )
fw . close ( )
# Edit it
editor = os . getenv ( ' EDITOR ' , ' vi ' )
subprocess . call ( ' %s %s ' % ( editor , path ) , shell = True )
# Open the tempfile to read
with open ( path , ' r ' ) as fr :
new_vm_config = fr . read ( )
fr . close ( )
# Delete the tempfile
os . unlink ( path )
# Show a diff and confirm
diff = list ( difflib . unified_diff ( current_vm_config . split ( ' \n ' ) , new_vm_config . split ( ' \n ' ) , fromfile = ' current ' , tofile = ' modified ' , fromfiledate = ' ' , tofiledate = ' ' , n = 3 , lineterm = ' ' ) )
if len ( diff ) < 1 :
click . echo ( ' Aborting with no modifications. ' )
exit ( 0 )
click . echo ( ' Pending modifications: ' )
click . echo ( ' ' )
for line in diff :
if re . match ( ' ^ \ + ' , line ) != None :
click . echo ( colorama . Fore . GREEN + line + colorama . Fore . RESET )
elif re . match ( ' ^ \ - ' , line ) != None :
click . echo ( colorama . Fore . RED + line + colorama . Fore . RESET )
elif re . match ( ' ^ \ ^ ' , line ) != None :
click . echo ( colorama . Fore . BLUE + line + colorama . Fore . RESET )
else :
click . echo ( line )
click . echo ( ' ' )
click . confirm ( ' Write modifications to Zookeeper? ' , abort = True )
2018-09-25 02:36:37 -04:00
if restart :
click . echo ( ' Writing modified config of VM " {} " and restarting. ' . format ( dom_name ) )
else :
click . echo ( ' Writing modified config of VM " {} " . ' . format ( dom_name ) )
2018-07-20 00:38:31 -04:00
# We're operating in replace mode
else :
# Open the XML file
new_vm_config = config . read ( )
config . close ( )
2018-09-25 02:36:37 -04:00
if restart :
2019-04-10 16:29:26 -04:00
click . echo ( ' Replacing config of VM " {} " with file " {} " and restarting. ' . format ( dom_name , config . name ) )
2018-09-25 02:36:37 -04:00
else :
2019-04-10 16:29:26 -04:00
click . echo ( ' Replacing config of VM " {} " with file " {} " . ' . format ( dom_name , config . name ) )
2018-07-20 00:38:31 -04:00
2018-09-25 02:32:08 -04:00
retcode , retmsg = pvc_vm . modify_vm ( zk_conn , domain , restart , new_vm_config )
2018-09-20 03:25:58 -04:00
cleanup ( retcode , retmsg , zk_conn )
2018-07-20 00:38:31 -04:00
2018-06-06 12:00:52 -04:00
###############################################################################
# pvc vm undefine
###############################################################################
2019-06-27 11:19:48 -04:00
@click.command ( name = ' undefine ' , short_help = ' Undefine a virtual machine. ' )
2018-06-16 22:22:07 -04:00
@click.argument (
' domain '
2018-06-06 12:00:52 -04:00
)
2018-09-20 03:25:58 -04:00
def vm_undefine ( domain ) :
2018-06-06 12:00:52 -04:00
"""
2019-06-27 11:19:48 -04:00
Stop virtual machine DOMAIN and remove it from the cluster database , preserving disks . DOMAIN may be a UUID or name .
2018-06-06 12:00:52 -04:00
"""
2018-06-06 12:28:15 -04:00
# Ensure at least one search method is set
2018-06-16 22:22:07 -04:00
if domain == None :
click . echo ( " ERROR: You must specify either a name or UUID value. " )
2018-08-29 21:31:47 -04:00
exit ( 1 )
2018-06-06 12:28:15 -04:00
2018-06-06 12:00:52 -04:00
# Open a Zookeeper connection
2018-09-21 23:43:30 -04:00
zk_conn = pvc_common . startZKConnection ( zk_host )
2019-05-20 22:15:28 -04:00
retcode , retmsg = pvc_vm . undefine_vm ( zk_conn , domain , is_cli = True )
2018-09-20 03:25:58 -04:00
cleanup ( retcode , retmsg , zk_conn )
2018-06-05 01:39:59 -04:00
2019-06-27 11:19:48 -04:00
###############################################################################
# pvc vm remove
###############################################################################
@click.command ( name = ' remove ' , short_help = ' Remove a virtual machine. ' )
@click.argument (
' domain '
)
def vm_remove ( domain ) :
"""
Stop virtual machine DOMAIN and remove it , along with all disks , from the cluster . DOMAIN may be a UUID or name .
"""
# Ensure at least one search method is set
if domain == None :
click . echo ( " ERROR: You must specify either a name or UUID value. " )
exit ( 1 )
# Open a Zookeeper connection
zk_conn = pvc_common . startZKConnection ( zk_host )
retcode , retmsg = pvc_vm . remove_vm ( zk_conn , domain , is_cli = True )
cleanup ( retcode , retmsg , zk_conn )
2019-03-12 21:09:54 -04:00
###############################################################################
# pvc vm dump
###############################################################################
@click.command ( name = ' dump ' , short_help = ' Dump a virtual machine XML to stdout. ' )
@click.argument (
' domain '
)
def vm_dump ( domain ) :
"""
Dump the Libvirt XML definition of virtual machine DOMAIN to stdout . DOMAIN may be a UUID or name .
"""
# Ensure at least one search method is set
if domain == None :
click . echo ( " ERROR: You must specify either a name or UUID value. " )
exit ( 1 )
# Open a Zookeeper connection
zk_conn = pvc_common . startZKConnection ( zk_host )
retcode , retmsg = pvc_vm . dump_vm ( zk_conn , domain )
cleanup ( retcode , retmsg , zk_conn )
2018-06-05 01:39:59 -04:00
###############################################################################
# pvc vm start
###############################################################################
@click.command ( name = ' start ' , short_help = ' Start up a defined virtual machine. ' )
2018-06-16 22:22:07 -04:00
@click.argument (
' domain '
2018-06-05 01:39:59 -04:00
)
2018-09-20 03:25:58 -04:00
def vm_start ( domain ) :
2018-06-05 01:39:59 -04:00
"""
2018-10-14 02:01:35 -04:00
Start virtual machine DOMAIN on its configured node . DOMAIN may be a UUID or name .
2018-06-05 01:39:59 -04:00
"""
# Open a Zookeeper connection
2018-09-21 23:43:30 -04:00
zk_conn = pvc_common . startZKConnection ( zk_host )
retcode , retmsg = pvc_vm . start_vm ( zk_conn , domain )
2018-09-20 03:25:58 -04:00
cleanup ( retcode , retmsg , zk_conn )
2018-06-05 01:39:59 -04:00
2018-06-13 12:49:51 -04:00
###############################################################################
# pvc vm restart
###############################################################################
2018-06-17 02:24:06 -04:00
@click.command ( name = ' restart ' , short_help = ' Restart a running virtual machine. ' )
2018-06-16 22:22:07 -04:00
@click.argument (
' domain '
2018-06-13 12:49:51 -04:00
)
2018-09-20 03:25:58 -04:00
def vm_restart ( domain ) :
2018-06-13 12:49:51 -04:00
"""
2018-06-17 02:24:06 -04:00
Restart running virtual machine DOMAIN . DOMAIN may be a UUID or name .
2018-06-13 12:49:51 -04:00
"""
# Open a Zookeeper connection
2018-09-21 23:43:30 -04:00
zk_conn = pvc_common . startZKConnection ( zk_host )
retcode , retmsg = pvc_vm . restart_vm ( zk_conn , domain )
2018-09-20 03:25:58 -04:00
cleanup ( retcode , retmsg , zk_conn )
2018-06-13 12:49:51 -04:00
2018-06-05 01:39:59 -04:00
###############################################################################
# pvc vm shutdown
###############################################################################
@click.command ( name = ' shutdown ' , short_help = ' Gracefully shut down a running virtual machine. ' )
2018-06-16 22:22:07 -04:00
@click.argument (
' domain '
2018-06-05 01:39:59 -04:00
)
2018-09-20 03:25:58 -04:00
def vm_shutdown ( domain ) :
2018-06-05 01:39:59 -04:00
"""
2018-06-16 22:22:07 -04:00
Gracefully shut down virtual machine DOMAIN . DOMAIN may be a UUID or name .
2018-06-05 01:39:59 -04:00
"""
# Open a Zookeeper connection
2018-09-21 23:43:30 -04:00
zk_conn = pvc_common . startZKConnection ( zk_host )
retcode , retmsg = pvc_vm . shutdown_vm ( zk_conn , domain )
2018-09-20 03:25:58 -04:00
cleanup ( retcode , retmsg , zk_conn )
2018-06-05 01:39:59 -04:00
###############################################################################
# pvc vm stop
###############################################################################
@click.command ( name = ' stop ' , short_help = ' Forcibly halt a running virtual machine. ' )
2018-06-16 22:22:07 -04:00
@click.argument (
' domain '
2018-06-05 01:39:59 -04:00
)
2018-09-20 03:25:58 -04:00
def vm_stop ( domain ) :
2018-06-05 01:39:59 -04:00
"""
2018-06-16 22:22:07 -04:00
Forcibly halt ( destroy ) running virtual machine DOMAIN . DOMAIN may be a UUID or name .
2018-06-05 01:39:59 -04:00
"""
# Open a Zookeeper connection
2018-09-21 23:43:30 -04:00
zk_conn = pvc_common . startZKConnection ( zk_host )
retcode , retmsg = pvc_vm . stop_vm ( zk_conn , domain )
2018-09-20 03:25:58 -04:00
cleanup ( retcode , retmsg , zk_conn )
2018-06-05 01:39:59 -04:00
2019-10-23 23:37:42 -04:00
###############################################################################
# pvc vm disable
###############################################################################
@click.command ( name = ' disable ' , short_help = ' Mark a virtual machine as disabled. ' )
@click.argument (
' domain '
)
def vm_disable ( domain ) :
"""
Prevent stopped virtual machine DOMAIN from being counted towards cluster health status . DOMAIN may be a UUID or name .
Use this option for VM that are stopped intentionally or long - term and which should not impact cluster health if stopped . A VM can be started directly from disable state .
"""
# Open a Zookeeper connection
zk_conn = pvc_common . startZKConnection ( zk_host )
retcode , retmsg = pvc_vm . disable_vm ( zk_conn , domain )
cleanup ( retcode , retmsg , zk_conn )
2018-06-10 21:03:41 -04:00
###############################################################################
# pvc vm move
###############################################################################
@click.command ( name = ' move ' , short_help = ' Permanently move a virtual machine to another node. ' )
2018-06-16 22:22:07 -04:00
@click.argument (
' domain '
2018-06-10 21:03:41 -04:00
)
@click.option (
2019-03-12 23:17:31 -04:00
' -t ' , ' --target ' , ' target_node ' , default = None ,
2018-10-14 02:01:35 -04:00
help = ' Target node to migrate to; autodetect if unspecified. '
2018-06-10 21:03:41 -04:00
)
2019-10-12 01:45:44 -04:00
def vm_move ( domain , target_node ) :
2018-06-10 21:03:41 -04:00
"""
2018-10-14 02:01:35 -04:00
Permanently move virtual machine DOMAIN , via live migration if running and possible , to another node . DOMAIN may be a UUID or name .
2018-06-10 21:03:41 -04:00
"""
# Open a Zookeeper connection
2018-09-21 23:43:30 -04:00
zk_conn = pvc_common . startZKConnection ( zk_host )
2019-10-12 01:45:44 -04:00
retcode , retmsg = pvc_vm . move_vm ( zk_conn , domain , target_node )
2018-09-20 03:25:58 -04:00
cleanup ( retcode , retmsg , zk_conn )
2018-06-10 21:03:41 -04:00
2018-06-05 22:06:08 -04:00
###############################################################################
# pvc vm migrate
###############################################################################
2018-06-22 12:24:53 -04:00
@click.command ( name = ' migrate ' , short_help = ' Temporarily migrate a virtual machine to another node. ' )
2018-06-16 22:22:07 -04:00
@click.argument (
' domain '
2018-06-05 22:06:08 -04:00
)
@click.option (
2019-03-12 23:17:31 -04:00
' -t ' , ' --target ' , ' target_node ' , default = None ,
2018-10-14 02:01:35 -04:00
help = ' Target node to migrate to; autodetect if unspecified. '
2018-06-05 22:06:08 -04:00
)
@click.option (
' -f ' , ' --force ' , ' force_migrate ' , is_flag = True , default = False ,
2019-07-07 15:10:48 -04:00
help = ' Force migrate an already migrated VM; does not replace an existing previous node value. '
2018-06-05 22:06:08 -04:00
)
2019-10-12 01:45:44 -04:00
def vm_migrate ( domain , target_node , force_migrate ) :
2018-06-05 01:39:59 -04:00
"""
2018-10-14 02:01:35 -04:00
Temporarily migrate running virtual machine DOMAIN , via live migration if possible , to another node . DOMAIN may be a UUID or name . If DOMAIN is not running , it will be started on the target node .
2018-06-05 01:39:59 -04:00
"""
2018-06-05 22:06:08 -04:00
# Open a Zookeeper connection
2018-09-21 23:43:30 -04:00
zk_conn = pvc_common . startZKConnection ( zk_host )
2019-10-12 01:45:44 -04:00
retcode , retmsg = pvc_vm . migrate_vm ( zk_conn , domain , target_node , force_migrate , is_cli = True )
2018-09-20 03:25:58 -04:00
cleanup ( retcode , retmsg , zk_conn )
2018-06-05 22:06:08 -04:00
###############################################################################
# pvc vm unmigrate
###############################################################################
2018-06-05 01:39:59 -04:00
@click.command ( name = ' unmigrate ' , short_help = ' Restore a migrated virtual machine to its original node. ' )
2018-06-16 22:22:07 -04:00
@click.argument (
' domain '
2018-06-05 22:06:08 -04:00
)
2018-09-20 03:25:58 -04:00
def vm_unmigrate ( domain ) :
2018-06-05 01:39:59 -04:00
"""
2018-10-14 02:01:35 -04:00
Restore previously migrated virtual machine DOMAIN , via live migration if possible , to its original node . DOMAIN may be a UUID or name . If DOMAIN is not running , it will be started on the target node .
2018-06-05 01:39:59 -04:00
"""
2018-06-05 22:06:08 -04:00
# Open a Zookeeper connection
2018-09-21 23:43:30 -04:00
zk_conn = pvc_common . startZKConnection ( zk_host )
retcode , retmsg = pvc_vm . unmigrate_vm ( zk_conn , domain )
2018-09-20 03:25:58 -04:00
cleanup ( retcode , retmsg , zk_conn )
2018-06-05 22:06:08 -04:00
2019-08-07 13:42:01 -04:00
###############################################################################
2019-08-07 17:50:25 -04:00
# pvc vm flush-locks
2019-08-07 13:42:01 -04:00
###############################################################################
2019-08-07 17:50:25 -04:00
@click.command ( name = ' flush-locks ' , short_help = ' Flush stale RBD locks for a virtual machine. ' )
2019-08-07 13:42:01 -04:00
@click.argument (
' domain '
)
def vm_flush_locks ( domain ) :
"""
Flush stale RBD locks for virtual machine DOMAIN . DOMAIN may be a UUID or name . DOMAIN must be in a stopped state before flushing locks .
"""
# Open a Zookeeper connection
zk_conn = pvc_common . startZKConnection ( zk_host )
retcode , retmsg = pvc_vm . flush_locks ( zk_conn , domain )
cleanup ( retcode , retmsg , zk_conn )
2018-06-05 22:06:08 -04:00
###############################################################################
2018-06-11 01:24:14 -04:00
# pvc vm info
2018-06-05 22:06:08 -04:00
###############################################################################
2018-07-18 22:28:49 -04:00
@click.command ( name = ' info ' , short_help = ' Show details of a VM object. ' )
2018-06-16 22:22:07 -04:00
@click.argument (
' domain '
2018-06-05 01:39:59 -04:00
)
2018-06-05 18:45:54 -04:00
@click.option (
' -l ' , ' --long ' , ' long_output ' , is_flag = True , default = False ,
help = ' Display more detailed information. '
)
2018-06-16 22:22:07 -04:00
def vm_info ( domain , long_output ) :
2018-06-05 01:39:59 -04:00
"""
2018-06-16 22:22:07 -04:00
Show information about virtual machine DOMAIN . DOMAIN may be a UUID or name .
2018-06-05 01:39:59 -04:00
"""
2018-06-05 22:06:08 -04:00
2018-09-21 23:43:30 -04:00
zk_conn = pvc_common . startZKConnection ( zk_host )
2019-05-20 22:15:28 -04:00
retcode , retdata = pvc_vm . get_info ( zk_conn , domain )
if retcode :
pvc_vm . format_info ( zk_conn , retdata , long_output )
retdata = ' '
cleanup ( retcode , retdata , zk_conn )
2018-06-05 01:39:59 -04:00
2019-04-11 19:06:06 -04:00
###############################################################################
# pvc vm log
###############################################################################
@click.command ( name = ' log ' , short_help = ' Show console logs of a VM object. ' )
@click.argument (
' domain '
)
@click.option (
' -l ' , ' --lines ' , ' lines ' , default = 1000 , show_default = True ,
help = ' Display this many log lines from the end of the log buffer. '
)
@click.option (
' -f ' , ' --follow ' , ' follow ' , is_flag = True , default = False ,
help = ' Follow the log buffer; output may be delayed by a few seconds relative to the live system. The --lines value defaults to 10 for the initial output. '
)
def vm_log ( domain , lines , follow ) :
"""
Show console logs of virtual machine DOMAIN on its current node in the ' less ' pager or continuously . DOMAIN may be a UUID or name . Note that migrating a VM to a different node will cause the log buffer to be overwritten by entries from the new node .
"""
# Open a Zookeeper connection
zk_conn = pvc_common . startZKConnection ( zk_host )
if follow :
# Handle the "new" default of the follow
if lines == 1000 :
lines = 10
retcode , retmsg = pvc_vm . follow_console_log ( zk_conn , domain , lines )
else :
retcode , retmsg = pvc_vm . get_console_log ( zk_conn , domain , lines )
cleanup ( retcode , retmsg , zk_conn )
2018-06-10 20:21:00 -04:00
###############################################################################
2018-06-11 01:24:14 -04:00
# pvc vm list
2018-06-10 20:21:00 -04:00
###############################################################################
2018-07-18 22:28:49 -04:00
@click.command ( name = ' list ' , short_help = ' List all VM objects. ' )
2018-07-19 21:58:11 -04:00
@click.argument (
' limit ' , default = None , required = False
)
2018-06-11 01:24:14 -04:00
@click.option (
2019-03-12 23:17:31 -04:00
' -t ' , ' --target ' , ' target_node ' , default = None ,
2019-03-20 11:31:54 -04:00
help = ' Limit list to VMs on the specified node. '
)
@click.option (
' -s ' , ' --state ' , ' target_state ' , default = None ,
help = ' Limit list to VMs in the specified state. '
2018-06-11 01:24:14 -04:00
)
2019-03-12 21:30:01 -04:00
@click.option (
' -r ' , ' --raw ' , ' raw ' , is_flag = True , default = False ,
2019-03-20 11:31:54 -04:00
help = ' Display the raw list of VM names only. '
2019-03-12 21:30:01 -04:00
)
2019-03-20 11:31:54 -04:00
def vm_list ( target_node , target_state , limit , raw ) :
2018-07-18 22:58:41 -04:00
"""
2018-07-19 21:58:11 -04:00
List all virtual machines in the cluster ; optionally only match names matching regex LIMIT .
2018-10-20 15:27:07 -04:00
NOTE : Red - coloured network lists indicate one or more configured networks are missing / invalid .
2018-07-18 22:58:41 -04:00
"""
2018-09-21 23:43:30 -04:00
zk_conn = pvc_common . startZKConnection ( zk_host )
2019-05-20 22:15:28 -04:00
retcode , retdata = pvc_vm . get_list ( zk_conn , target_node , target_state , limit )
if retcode :
pvc_vm . format_list ( zk_conn , retdata , raw )
retdata = ' '
cleanup ( retcode , retdata , zk_conn )
2018-06-10 20:21:00 -04:00
2018-09-21 23:43:30 -04:00
###############################################################################
# pvc network
###############################################################################
@click.group ( name = ' network ' , short_help = ' Manage a PVC virtual network. ' , context_settings = CONTEXT_SETTINGS )
def cli_network ( ) :
"""
Manage the state of a VXLAN network in the PVC cluster .
"""
pass
###############################################################################
# pvc network add
###############################################################################
@click.command ( name = ' add ' , short_help = ' Add a new virtual network to the cluster. ' )
@click.option (
' -d ' , ' --description ' , ' description ' ,
2018-10-17 00:23:27 -04:00
required = True ,
2018-11-13 01:22:15 -05:00
help = ' Description of the network; must be unique and not contain whitespace. '
2018-09-28 20:42:24 -04:00
)
@click.option (
2019-03-15 11:28:49 -04:00
' -p ' , ' --type ' , ' nettype ' ,
2018-09-28 20:42:24 -04:00
required = True ,
2019-03-15 11:28:49 -04:00
type = click . Choice ( [ ' managed ' , ' bridged ' ] ) ,
help = ' Network type; managed networks control IP addressing; bridged networks are simple vLAN bridges. All subsequent options are unused for bridged networks. '
)
@click.option (
' -n ' , ' --domain ' , ' domain ' ,
default = None ,
2018-09-28 20:42:24 -04:00
help = ' Domain name of the network. '
2018-09-21 23:43:30 -04:00
)
@click.option (
' -i ' , ' --ipnet ' , ' ip_network ' ,
2018-11-13 01:22:15 -05:00
default = None ,
help = ' CIDR-format IPv4 network address for subnet. '
)
@click.option (
' -i6 ' , ' --ipnet6 ' , ' ip6_network ' ,
default = None ,
help = ' CIDR-format IPv6 network address for subnet; should be /64 or larger ending " ::/YY " . '
2018-09-21 23:43:30 -04:00
)
@click.option (
' -g ' , ' --gateway ' , ' ip_gateway ' ,
2018-11-13 01:22:15 -05:00
default = None ,
help = ' Default IPv4 gateway address for subnet. '
)
@click.option (
' -g6 ' , ' --gateway6 ' , ' ip6_gateway ' ,
default = None ,
help = ' Default IPv6 gateway address for subnet. [default: " X::1 " ] '
2018-09-21 23:43:30 -04:00
)
@click.option (
2018-09-23 15:26:20 -04:00
' --dhcp/--no-dhcp ' , ' dhcp_flag ' ,
2018-09-21 23:43:30 -04:00
is_flag = True ,
2019-03-15 11:28:49 -04:00
default = False ,
2018-11-13 01:22:15 -05:00
help = ' Enable/disable IPv4 DHCP for clients on subnet. '
2018-09-21 23:43:30 -04:00
)
2018-09-29 02:54:48 -04:00
@click.option (
' --dhcp-start ' , ' dhcp_start ' ,
default = None ,
2018-11-13 01:22:15 -05:00
help = ' IPv4 DHCP range start address. '
2018-09-29 02:54:48 -04:00
)
@click.option (
' --dhcp-end ' , ' dhcp_end ' ,
default = None ,
2018-11-13 01:22:15 -05:00
help = ' IPv4 DHCP range end address. '
2018-09-29 02:54:48 -04:00
)
2018-09-21 23:43:30 -04:00
@click.argument (
' vni '
)
2019-03-15 11:28:49 -04:00
def net_add ( vni , description , nettype , domain , ip_network , ip_gateway , ip6_network , ip6_gateway , dhcp_flag , dhcp_start , dhcp_end ) :
2018-09-21 23:43:30 -04:00
"""
Add a new virtual network with VXLAN identifier VNI to the cluster .
2019-03-15 11:28:49 -04:00
Examples :
pvc network add 101 - - type bridged
> Creates vLAN 101 and a simple bridge on the VNI dev interface .
pvc network add 1001 - - type managed - - domain test . local - - ipnet 10.1 .1 .0 / 24 - - gateway 10.1 .1 .1
> Creates a VXLAN with ID 1001 on the VNI dev interface , with IPv4 managed networking .
2018-11-13 01:22:15 -05:00
IPv6 is fully supported with - - ipnet6 and - - gateway6 in addition to or instead of IPv4 . PVC will configure DHCPv6 in a semi - managed configuration for the network if set .
2018-09-21 23:43:30 -04:00
"""
2019-03-15 11:28:49 -04:00
if nettype == ' managed ' and not ip_network and not ip6_network :
2018-11-13 01:22:15 -05:00
click . echo ( ' Error: At least one of " -i " / " --ipnet " or " -i6 " / " --ipnet6 " must be specified. ' )
2019-03-15 11:28:49 -04:00
exit ( 1 )
2018-11-13 01:22:15 -05:00
2018-09-21 23:43:30 -04:00
zk_conn = pvc_common . startZKConnection ( zk_host )
2019-03-15 11:28:49 -04:00
retcode , retmsg = pvc_network . add_network ( zk_conn , vni , description , nettype , domain , ip_network , ip_gateway , ip6_network , ip6_gateway , dhcp_flag , dhcp_start , dhcp_end )
2018-09-21 23:43:30 -04:00
cleanup ( retcode , retmsg , zk_conn )
2018-09-23 15:26:20 -04:00
###############################################################################
# pvc network modify
###############################################################################
@click.command ( name = ' modify ' , short_help = ' Modify an existing virtual network. ' )
@click.option (
' -d ' , ' --description ' , ' description ' ,
default = None ,
2018-10-17 00:23:27 -04:00
help = ' Description of the network; must be unique and not contain whitespace. '
2018-09-23 15:26:20 -04:00
)
2018-10-03 20:22:42 -04:00
@click.option (
' -n ' , ' --domain ' , ' domain ' ,
default = None ,
help = ' Domain name of the network. '
)
2018-09-23 15:26:20 -04:00
@click.option (
2018-11-14 00:19:43 -05:00
' -i ' , ' --ipnet ' , ' ip4_network ' ,
2018-09-23 15:26:20 -04:00
default = None ,
2018-11-13 01:22:15 -05:00
help = ' CIDR-format IPv4 network address for subnet. '
)
@click.option (
' -i6 ' , ' --ipnet6 ' , ' ip6_network ' ,
default = None ,
help = ' CIDR-format IPv6 network address for subnet. '
2018-09-23 15:26:20 -04:00
)
@click.option (
2018-11-14 00:19:43 -05:00
' -g ' , ' --gateway ' , ' ip4_gateway ' ,
2018-09-23 15:26:20 -04:00
default = None ,
2018-11-13 01:22:15 -05:00
help = ' Default IPv4 gateway address for subnet. '
)
@click.option (
' -g6 ' , ' --gateway6 ' , ' ip6_gateway ' ,
default = None ,
help = ' Default IPv6 gateway address for subnet. '
2018-09-23 15:26:20 -04:00
)
@click.option (
' --dhcp/--no-dhcp ' , ' dhcp_flag ' ,
is_flag = True ,
2018-10-17 00:23:27 -04:00
default = None ,
2018-09-23 15:26:20 -04:00
help = ' Enable/disable DHCP for clients on subnet. '
)
2018-10-03 20:22:42 -04:00
@click.option (
' --dhcp-start ' , ' dhcp_start ' ,
default = None ,
help = ' DHCP range start address. '
)
@click.option (
' --dhcp-end ' , ' dhcp_end ' ,
default = None ,
help = ' DHCP range end address. '
)
2018-09-23 15:26:20 -04:00
@click.argument (
' vni '
)
2018-11-14 00:19:43 -05:00
def net_modify ( vni , description , domain , ip6_network , ip6_gateway , ip4_network , ip4_gateway , dhcp_flag , dhcp_start , dhcp_end ) :
2018-09-23 15:26:20 -04:00
"""
Modify details of virtual network VNI . All fields optional ; only specified fields will be updated .
Example :
2018-10-03 20:22:42 -04:00
pvc network modify 1001 - - gateway 10.1 .1 .1 - - dhcp
2018-09-23 15:26:20 -04:00
"""
zk_conn = pvc_common . startZKConnection ( zk_host )
2018-11-14 00:19:43 -05:00
retcode , retmsg = pvc_network . modify_network ( zk_conn , vni , description = description , domain = domain , ip6_network = ip6_network , ip6_gateway = ip6_gateway , ip4_network = ip4_network , ip4_gateway = ip4_gateway , dhcp_flag = dhcp_flag , dhcp_start = dhcp_start , dhcp_end = dhcp_end )
2018-09-23 15:26:20 -04:00
cleanup ( retcode , retmsg , zk_conn )
2018-09-21 23:43:30 -04:00
###############################################################################
# pvc network remove
###############################################################################
@click.command ( name = ' remove ' , short_help = ' Remove a virtual network from the cluster. ' )
@click.argument (
' net '
)
def net_remove ( net ) :
"""
Remove an existing virtual network NET from the cluster ; NET can be either a VNI or description .
WARNING : PVC does not verify whether clients are still present in this network . Before removing , ensure
that all client VMs have been removed from the network or undefined behaviour may occur .
"""
zk_conn = pvc_common . startZKConnection ( zk_host )
retcode , retmsg = pvc_network . remove_network ( zk_conn , net )
cleanup ( retcode , retmsg , zk_conn )
###############################################################################
# pvc network info
###############################################################################
@click.command ( name = ' info ' , short_help = ' Show details of a network. ' )
@click.argument (
' vni '
)
2018-09-25 01:32:03 -04:00
@click.option (
' -l ' , ' --long ' , ' long_output ' , is_flag = True , default = False ,
help = ' Display more detailed information. '
)
def net_info ( vni , long_output ) :
2018-09-21 23:43:30 -04:00
"""
Show information about virtual network VNI .
"""
# Open a Zookeeper connection
zk_conn = pvc_common . startZKConnection ( zk_host )
2019-07-04 23:01:22 -04:00
retcode , retdata = pvc_network . get_info ( zk_conn , vni )
if retcode :
pvc_network . format_info ( retdata , long_output )
retdata = ' '
cleanup ( retcode , retdata , zk_conn )
2018-09-21 23:43:30 -04:00
###############################################################################
# pvc network list
###############################################################################
@click.command ( name = ' list ' , short_help = ' List all VM objects. ' )
@click.argument (
' limit ' , default = None , required = False
)
def net_list ( limit ) :
"""
List all virtual networks in the cluster ; optionally only match VNIs or Descriptions matching regex LIMIT .
"""
zk_conn = pvc_common . startZKConnection ( zk_host )
2019-07-04 23:01:22 -04:00
retcode , retdata = pvc_network . get_list ( zk_conn , limit )
if retcode :
pvc_network . format_list ( retdata )
retdata = ' '
cleanup ( retcode , retdata , zk_conn )
2018-09-21 23:43:30 -04:00
2018-09-28 20:31:56 -04:00
###############################################################################
# pvc network dhcp
###############################################################################
2018-11-13 01:22:15 -05:00
@click.group ( name = ' dhcp ' , short_help = ' Manage IPv4 DHCP leases in a PVC virtual network. ' , context_settings = CONTEXT_SETTINGS )
2018-09-28 20:31:56 -04:00
def net_dhcp ( ) :
"""
2018-11-13 01:22:15 -05:00
Manage host IPv4 DHCP leases of a VXLAN network in the PVC cluster .
2018-09-28 20:31:56 -04:00
"""
pass
2018-10-03 19:23:46 -04:00
###############################################################################
# pvc network dhcp list
###############################################################################
@click.command ( name = ' list ' , short_help = ' List active DHCP leases. ' )
@click.argument (
' net '
)
@click.argument (
' limit ' , default = None , required = False
)
def net_dhcp_list ( net , limit ) :
"""
List all DHCP leases in virtual network NET ; optionally only match elements matching regex LIMIT ; NET can be either a VNI or description .
"""
zk_conn = pvc_common . startZKConnection ( zk_host )
2019-07-04 23:01:22 -04:00
retcode , retdata = pvc_network . get_list_dhcp ( zk_conn , net , limit , only_static = False )
if retcode :
pvc_network . format_list_dhcp ( retdata )
retdata = ' '
cleanup ( retcode , retdata , zk_conn )
2018-09-28 20:31:56 -04:00
###############################################################################
2018-10-03 19:23:46 -04:00
# pvc network dhcp static
###############################################################################
@click.group ( name = ' static ' , short_help = ' Manage DHCP static reservations in a PVC virtual network. ' , context_settings = CONTEXT_SETTINGS )
def net_dhcp_static ( ) :
"""
Manage host DHCP static reservations of a VXLAN network in the PVC cluster .
"""
pass
2018-09-28 20:31:56 -04:00
###############################################################################
2018-10-03 19:23:46 -04:00
# pvc network dhcp static add
###############################################################################
@click.command ( name = ' add ' , short_help = ' Add a DHCP static reservation. ' )
2018-09-28 20:31:56 -04:00
@click.argument (
' net '
)
@click.argument (
' ipaddr '
)
@click.argument (
2018-10-02 00:08:45 -04:00
' hostname '
2018-09-28 20:31:56 -04:00
)
2018-09-30 12:43:56 -04:00
@click.argument (
2018-10-02 00:08:45 -04:00
' macaddr '
2018-09-30 12:43:56 -04:00
)
2018-10-03 19:23:46 -04:00
def net_dhcp_static_add ( net , ipaddr , macaddr , hostname ) :
2018-09-28 20:31:56 -04:00
"""
2018-10-03 19:23:46 -04:00
Add a new DHCP static reservation of IP address IPADDR with hostname HOSTNAME for MAC address MACADDR to virtual network NET ; NET can be either a VNI or description .
2018-09-28 20:31:56 -04:00
"""
zk_conn = pvc_common . startZKConnection ( zk_host )
2018-09-30 12:43:56 -04:00
retcode , retmsg = pvc_network . add_dhcp_reservation ( zk_conn , net , ipaddr , macaddr , hostname )
2018-09-28 20:31:56 -04:00
cleanup ( retcode , retmsg , zk_conn )
###############################################################################
2018-10-03 19:23:46 -04:00
# pvc network dhcp static remove
2018-09-28 20:31:56 -04:00
###############################################################################
2018-10-03 19:23:46 -04:00
@click.command ( name = ' remove ' , short_help = ' Remove a DHCP static reservation. ' )
2018-09-28 20:31:56 -04:00
@click.argument (
' net '
)
@click.argument (
2018-10-03 19:23:46 -04:00
' reservation '
2018-09-28 20:31:56 -04:00
)
2018-10-03 19:23:46 -04:00
def net_dhcp_static_remove ( net , reservation ) :
2018-09-28 20:31:56 -04:00
"""
2018-10-03 19:23:46 -04:00
Remove a DHCP static reservation RESERVATION from virtual network NET ; RESERVATION can be either a MAC address , an IP address , or a hostname ; NET can be either a VNI or description .
2018-09-28 20:31:56 -04:00
"""
zk_conn = pvc_common . startZKConnection ( zk_host )
2018-10-03 19:23:46 -04:00
retcode , retmsg = pvc_network . remove_dhcp_reservation ( zk_conn , net , reservation )
2018-09-28 20:31:56 -04:00
cleanup ( retcode , retmsg , zk_conn )
###############################################################################
2018-10-03 19:23:46 -04:00
# pvc network dhcp static list
2018-09-28 20:31:56 -04:00
###############################################################################
2018-10-03 19:23:46 -04:00
@click.command ( name = ' list ' , short_help = ' List DHCP static reservations. ' )
2018-09-28 20:31:56 -04:00
@click.argument (
' net '
)
@click.argument (
' limit ' , default = None , required = False
)
2018-10-03 19:23:46 -04:00
def net_dhcp_static_list ( net , limit ) :
2018-09-28 20:31:56 -04:00
"""
2018-10-03 19:23:46 -04:00
List all DHCP static reservations in virtual network NET ; optionally only match elements matching regex LIMIT ; NET can be either a VNI or description .
2018-09-28 20:31:56 -04:00
"""
zk_conn = pvc_common . startZKConnection ( zk_host )
2019-07-04 23:01:22 -04:00
retcode , retdata = pvc_network . get_list_dhcp ( zk_conn , net , limit , only_static = True )
if retcode :
pvc_network . format_list_dhcp ( retdata )
retdata = ' '
cleanup ( retcode , retdata , zk_conn )
2018-09-28 20:31:56 -04:00
###############################################################################
# pvc network acl
###############################################################################
@click.group ( name = ' acl ' , short_help = ' Manage a PVC virtual network firewall ACL rule. ' , context_settings = CONTEXT_SETTINGS )
def net_acl ( ) :
"""
Manage firewall ACLs of a VXLAN network in the PVC cluster .
"""
pass
2018-09-21 23:43:30 -04:00
2018-10-17 00:23:27 -04:00
###############################################################################
# pvc network acl add
###############################################################################
@click.command ( name = ' add ' , short_help = ' Add firewall ACL. ' )
@click.option (
' --in/--out ' , ' direction ' ,
is_flag = True ,
required = True ,
default = None ,
help = ' Inbound or outbound ruleset. '
)
@click.option (
' -d ' , ' --description ' , ' description ' ,
required = True ,
help = ' Description of the ACL; must be unique and not contain whitespace. '
)
@click.option (
' -r ' , ' --rule ' , ' rule ' ,
required = True ,
help = ' NFT firewall rule. '
)
@click.option (
' -o ' , ' --order ' , ' order ' ,
default = None ,
help = ' Order of rule in the chain (see " list " ); defaults to last. '
)
@click.argument (
' net '
)
def net_acl_add ( net , direction , description , rule , order ) :
"""
Add a new NFT firewall rule to network NET ; the rule is a literal NFT rule belonging to the forward table for the client network ; NET can be either a VNI or description .
NOTE : All client networks are default - allow in both directions ; deny rules MUST be added here at the end of the sequence for a default - deny setup .
NOTE : Ordering places the rule at the specified ID , not before it ; the old rule of that ID and all subsequent rules will be moved down .
Example :
pvc network acl add 1001 - - in - - rule " tcp dport 22 ct state new accept " - - description " ssh-in " - - order 3
"""
zk_conn = pvc_common . startZKConnection ( zk_host )
retcode , retmsg = pvc_network . add_acl ( zk_conn , net , direction , description , rule , order )
cleanup ( retcode , retmsg , zk_conn )
###############################################################################
# pvc network acl remove
###############################################################################
@click.command ( name = ' remove ' , short_help = ' Remove firewall ACL. ' )
@click.option (
' --in/--out ' , ' direction ' ,
is_flag = True ,
required = True ,
default = None ,
help = ' Inbound or outbound rule set. '
)
@click.argument (
' net '
)
@click.argument (
' rule ' ,
)
def net_acl_remove ( net , rule , direction ) :
"""
Remove an NFT firewall rule RULE from network NET ; RULE can be either a sequence order identifier or description ; NET can be either a VNI or description . "
"""
zk_conn = pvc_common . startZKConnection ( zk_host )
retcode , retmsg = pvc_network . remove_acl ( zk_conn , net , rule , direction )
cleanup ( retcode , retmsg , zk_conn )
###############################################################################
# pvc network acl list
###############################################################################
@click.command ( name = ' list ' , short_help = ' List firewall ACLs. ' )
@click.option (
' --in/--out ' , ' direction ' ,
is_flag = True ,
2018-10-17 20:05:22 -04:00
required = False ,
2018-10-17 00:23:27 -04:00
default = None ,
2018-10-17 20:05:22 -04:00
help = ' Inbound or outbound rule set only. '
2018-10-17 00:23:27 -04:00
)
@click.argument (
' net '
)
@click.argument (
' limit ' , default = None , required = False
)
def net_acl_list ( net , limit , direction ) :
"""
List all NFT firewall rules in network NET ; optionally only match elements matching description regex LIMIT ; NET can be either a VNI or description .
"""
2018-09-21 23:43:30 -04:00
2018-10-17 00:23:27 -04:00
zk_conn = pvc_common . startZKConnection ( zk_host )
2019-07-04 23:01:22 -04:00
retcode , retdata = pvc_network . get_list_acl ( zk_conn , net , limit , direction )
if retcode :
pvc_network . format_list_acl ( retdata )
retdata = ' '
cleanup ( retcode , retdata , zk_conn )
2018-09-21 23:43:30 -04:00
2018-10-27 18:11:58 -04:00
###############################################################################
2019-07-10 15:14:17 -04:00
# pvc storage
###############################################################################
# Note: The prefix `storage` allows future potential storage subsystems.
# Since Ceph is the only section not abstracted by PVC directly
# (i.e. it references Ceph-specific concepts), this makes more
# sense in the long-term.
###############################################################################
@click.group ( name = ' storage ' , short_help = ' Manage the PVC storage cluster. ' , context_settings = CONTEXT_SETTINGS )
def cli_storage ( ) :
"""
Manage the storage of the PVC cluster .
"""
pass
###############################################################################
# pvc storage ceph
2018-10-27 18:11:58 -04:00
###############################################################################
@click.group ( name = ' ceph ' , short_help = ' Manage the PVC Ceph storage cluster. ' , context_settings = CONTEXT_SETTINGS )
def cli_ceph ( ) :
"""
Manage the Ceph storage of the PVC cluster .
2018-10-31 23:38:17 -04:00
NOTE : The PVC Ceph interface is limited to the most common tasks . Any other administrative tasks must be performed on a node directly .
2018-10-27 18:11:58 -04:00
"""
pass
###############################################################################
2019-07-10 15:14:17 -04:00
# pvc storage ceph status
2018-10-27 18:11:58 -04:00
###############################################################################
@click.command ( name = ' status ' , short_help = ' Show storage cluster status. ' )
def ceph_status ( ) :
"""
Show detailed status of the storage cluster .
"""
zk_conn = pvc_common . startZKConnection ( zk_host )
2019-07-05 00:29:47 -04:00
retcode , retdata = pvc_ceph . get_status ( zk_conn )
2019-07-05 00:44:40 -04:00
if retcode :
2019-07-08 10:56:33 -04:00
pvc_ceph . format_raw_output ( retdata )
retdata = ' '
cleanup ( retcode , retdata , zk_conn )
###############################################################################
2019-07-10 15:14:17 -04:00
# pvc storage ceph df
2019-07-08 10:56:33 -04:00
###############################################################################
@click.command ( name = ' df ' , short_help = ' Show storage cluster utilization. ' )
def ceph_radosdf ( ) :
"""
Show utilization of the storage cluster .
"""
zk_conn = pvc_common . startZKConnection ( zk_host )
retcode , retdata = pvc_ceph . get_radosdf ( zk_conn )
if retcode :
pvc_ceph . format_raw_output ( retdata )
2019-07-05 00:29:47 -04:00
retdata = ' '
cleanup ( retcode , retdata , zk_conn )
2018-10-27 18:11:58 -04:00
###############################################################################
2019-07-10 15:14:17 -04:00
# pvc storage ceph osd
2018-10-27 18:11:58 -04:00
###############################################################################
@click.group ( name = ' osd ' , short_help = ' Manage OSDs in the PVC storage cluster. ' , context_settings = CONTEXT_SETTINGS )
def ceph_osd ( ) :
"""
Manage the Ceph OSDs of the PVC cluster .
"""
pass
2018-10-28 22:15:25 -04:00
###############################################################################
2019-07-10 15:14:17 -04:00
# pvc storage ceph osd add
2018-10-28 22:15:25 -04:00
###############################################################################
@click.command ( name = ' add ' , short_help = ' Add new OSD. ' )
@click.argument (
' node '
)
@click.argument (
' device '
)
2018-11-01 23:03:27 -04:00
@click.option (
' -w ' , ' --weight ' , ' weight ' ,
default = 1.0 , show_default = True ,
help = ' Weight of the OSD within the CRUSH map. '
)
2019-06-21 15:52:28 -04:00
@click.option (
' --yes ' , ' yes ' ,
is_flag = True , default = False ,
help = ' Pre-confirm the disk destruction. '
)
def ceph_osd_add ( node , device , weight , yes ) :
2018-10-28 22:15:25 -04:00
"""
Add a new Ceph OSD on node NODE with block device DEVICE to the cluster .
"""
2019-06-21 15:52:28 -04:00
if not yes :
2019-06-21 15:54:54 -04:00
click . echo ( ' DANGER: This will completely destroy all data on {} disk {} . ' . format ( node , device ) )
2019-06-21 15:52:28 -04:00
choice = input ( ' Are you sure you want to do this? (y/N) ' )
if choice != ' y ' and choice != ' Y ' :
exit ( 0 )
2018-10-28 22:15:25 -04:00
zk_conn = pvc_common . startZKConnection ( zk_host )
2018-11-01 23:03:27 -04:00
retcode , retmsg = pvc_ceph . add_osd ( zk_conn , node , device , weight )
2018-10-28 22:15:25 -04:00
cleanup ( retcode , retmsg , zk_conn )
###############################################################################
2019-07-10 15:14:17 -04:00
# pvc storage ceph osd remove
2018-10-28 22:15:25 -04:00
###############################################################################
@click.command ( name = ' remove ' , short_help = ' Remove OSD. ' )
@click.argument (
' osdid '
)
2019-06-21 15:52:28 -04:00
@click.option (
' --yes ' , ' yes ' ,
is_flag = True , default = False ,
help = ' Pre-confirm the removal. '
)
def ceph_osd_remove ( osdid , yes ) :
2018-10-28 22:15:25 -04:00
"""
Remove a Ceph OSD with ID OSDID from the cluster .
"""
2019-06-21 15:52:28 -04:00
if not yes :
click . echo ( ' DANGER: This will completely remove OSD {} from cluster. OSDs will rebalance. ' . format ( osdid ) )
choice = input ( ' Are you sure you want to do this? (y/N) ' )
if choice != ' y ' and choice != ' Y ' :
exit ( 0 )
2018-10-28 22:15:25 -04:00
zk_conn = pvc_common . startZKConnection ( zk_host )
retcode , retmsg = pvc_ceph . remove_osd ( zk_conn , osdid )
cleanup ( retcode , retmsg , zk_conn )
2018-11-01 22:00:59 -04:00
###############################################################################
2019-07-10 15:14:17 -04:00
# pvc storage ceph osd in
2018-11-01 22:00:59 -04:00
###############################################################################
@click.command ( name = ' in ' , short_help = ' Online OSD. ' )
@click.argument (
' osdid '
)
def ceph_osd_in ( osdid ) :
"""
Set a Ceph OSD with ID OSDID online in the cluster .
"""
zk_conn = pvc_common . startZKConnection ( zk_host )
retcode , retmsg = pvc_ceph . in_osd ( zk_conn , osdid )
cleanup ( retcode , retmsg , zk_conn )
###############################################################################
2019-07-10 15:14:17 -04:00
# pvc storage ceph osd out
2018-11-01 22:00:59 -04:00
###############################################################################
@click.command ( name = ' out ' , short_help = ' Offline OSD. ' )
@click.argument (
' osdid '
)
def ceph_osd_out ( osdid ) :
"""
Set a Ceph OSD with ID OSDID offline in the cluster .
"""
zk_conn = pvc_common . startZKConnection ( zk_host )
retcode , retmsg = pvc_ceph . out_osd ( zk_conn , osdid )
cleanup ( retcode , retmsg , zk_conn )
###############################################################################
2019-07-10 15:14:17 -04:00
# pvc storage ceph osd set
2018-11-01 22:00:59 -04:00
###############################################################################
@click.command ( name = ' set ' , short_help = ' Set property. ' )
@click.argument (
' osd_property '
)
def ceph_osd_set ( osd_property ) :
"""
Set a Ceph OSD property OSD_PROPERTY on the cluster .
Valid properties are :
full | pause | noup | nodown | noout | noin | nobackfill | norebalance | norecover | noscrub | nodeep - scrub | notieragent | sortbitwise | recovery_deletes | require_jewel_osds | require_kraken_osds
"""
zk_conn = pvc_common . startZKConnection ( zk_host )
retcode , retmsg = pvc_ceph . set_osd ( zk_conn , osd_property )
cleanup ( retcode , retmsg , zk_conn )
###############################################################################
2019-07-10 15:14:17 -04:00
# pvc storage ceph osd unset
2018-11-01 22:00:59 -04:00
###############################################################################
@click.command ( name = ' unset ' , short_help = ' Unset property. ' )
@click.argument (
' osd_property '
)
def ceph_osd_unset ( osd_property ) :
"""
Unset a Ceph OSD property OSD_PROPERTY on the cluster .
Valid properties are :
full | pause | noup | nodown | noout | noin | nobackfill | norebalance | norecover | noscrub | nodeep - scrub | notieragent | sortbitwise | recovery_deletes | require_jewel_osds | require_kraken_osds
"""
zk_conn = pvc_common . startZKConnection ( zk_host )
retcode , retmsg = pvc_ceph . unset_osd ( zk_conn , osd_property )
cleanup ( retcode , retmsg , zk_conn )
2018-10-30 09:17:32 -04:00
###############################################################################
2019-07-10 15:14:17 -04:00
# pvc storage ceph osd list
2018-10-30 09:17:32 -04:00
###############################################################################
@click.command ( name = ' list ' , short_help = ' List cluster OSDs. ' )
@click.argument (
' limit ' , default = None , required = False
)
def ceph_osd_list ( limit ) :
"""
2019-06-19 00:12:44 -04:00
List all Ceph OSDs in the cluster ; optionally only match elements matching ID regex LIMIT .
2018-10-30 09:17:32 -04:00
"""
zk_conn = pvc_common . startZKConnection ( zk_host )
2019-07-05 00:29:47 -04:00
retcode , retdata = pvc_ceph . get_list_osd ( zk_conn , limit )
if retcode :
pvc_ceph . format_list_osd ( retdata )
retdata = ' '
cleanup ( retcode , retdata , zk_conn )
2018-10-30 09:17:32 -04:00
2018-10-27 18:11:58 -04:00
###############################################################################
2019-07-10 15:14:17 -04:00
# pvc storage ceph pool
2018-10-27 18:11:58 -04:00
###############################################################################
@click.group ( name = ' pool ' , short_help = ' Manage RBD pools in the PVC storage cluster. ' , context_settings = CONTEXT_SETTINGS )
def ceph_pool ( ) :
"""
Manage the Ceph RBD pools of the PVC cluster .
"""
pass
2018-09-21 23:43:30 -04:00
2018-10-31 23:38:17 -04:00
###############################################################################
2019-07-10 15:14:17 -04:00
# pvc storage ceph pool add
2018-10-31 23:38:17 -04:00
###############################################################################
@click.command ( name = ' add ' , short_help = ' Add new RBD pool. ' )
@click.argument (
' name '
)
@click.argument (
' pgs '
)
2019-08-23 14:12:15 -04:00
@click.option (
' --replcfg ' , ' replcfg ' ,
default = ' copies=3,mincopies=2 ' , show_default = True , required = False ,
help = """
The replication configuration , specifying both a " copies " and " mincopies " value , separated by a
comma , e . g . " copies=3,mincopies=2 " . The " copies " value specifies the total number of replicas and should not exceed the total number of nodes ; the " mincopies " value specifies the minimum number of available copies to allow writes . For additional details please see the Cluster Architecture documentation .
"""
)
def ceph_pool_add ( name , pgs , replcfg ) :
2018-10-31 23:38:17 -04:00
"""
Add a new Ceph RBD pool with name NAME and PGS placement groups .
2019-08-23 14:12:15 -04:00
2018-10-31 23:38:17 -04:00
"""
zk_conn = pvc_common . startZKConnection ( zk_host )
2019-08-23 14:12:15 -04:00
retcode , retmsg = pvc_ceph . add_pool ( zk_conn , name , pgs , replcfg )
2018-10-31 23:38:17 -04:00
cleanup ( retcode , retmsg , zk_conn )
###############################################################################
2019-07-10 15:14:17 -04:00
# pvc storage ceph pool remove
2018-10-31 23:38:17 -04:00
###############################################################################
@click.command ( name = ' remove ' , short_help = ' Remove RBD pool. ' )
@click.argument (
' name '
)
2019-06-21 15:52:28 -04:00
@click.option (
' --yes ' , ' yes ' ,
is_flag = True , default = False ,
help = ' Pre-confirm the removal. '
)
def ceph_pool_remove ( name , yes ) :
2018-10-31 23:38:17 -04:00
"""
Remove a Ceph RBD pool with name NAME and all volumes on it .
"""
2019-06-21 15:52:28 -04:00
if not yes :
click . echo ( ' DANGER: This will completely remove pool {} and all data contained in it. ' . format ( name ) )
choice = input ( ' Are you sure you want to do this? (y/N) ' )
if choice != ' y ' and choice != ' Y ' :
pool_name_check = input ( ' Please enter the pool name to confirm: ' )
if pool_name_check != name :
exit ( 0 )
zk_conn = pvc_common . startZKConnection ( zk_host )
retcode , retmsg = pvc_ceph . remove_pool ( zk_conn , name )
cleanup ( retcode , retmsg , zk_conn )
2018-10-31 23:38:17 -04:00
###############################################################################
2019-07-10 15:14:17 -04:00
# pvc storage ceph pool list
2018-10-31 23:38:17 -04:00
###############################################################################
@click.command ( name = ' list ' , short_help = ' List cluster RBD pools. ' )
@click.argument (
' limit ' , default = None , required = False
)
def ceph_pool_list ( limit ) :
"""
2019-06-19 00:12:44 -04:00
List all Ceph RBD pools in the cluster ; optionally only match elements matching name regex LIMIT .
2018-10-31 23:38:17 -04:00
"""
zk_conn = pvc_common . startZKConnection ( zk_host )
2019-07-05 00:29:47 -04:00
retcode , retdata = pvc_ceph . get_list_pool ( zk_conn , limit )
if retcode :
pvc_ceph . format_list_pool ( retdata )
retdata = ' '
cleanup ( retcode , retdata , zk_conn )
2018-10-31 23:38:17 -04:00
2019-06-19 00:23:14 -04:00
###############################################################################
2019-07-10 15:14:17 -04:00
# pvc storage ceph volume
2019-06-19 00:23:14 -04:00
###############################################################################
@click.group ( name = ' volume ' , short_help = ' Manage RBD volumes in the PVC storage cluster. ' , context_settings = CONTEXT_SETTINGS )
def ceph_volume ( ) :
"""
Manage the Ceph RBD volumes of the PVC cluster .
"""
pass
2019-06-19 00:12:44 -04:00
###############################################################################
2019-07-10 15:14:17 -04:00
# pvc storage ceph volume add
2019-06-19 00:12:44 -04:00
###############################################################################
@click.command ( name = ' add ' , short_help = ' Add new RBD volume. ' )
@click.argument (
' pool '
)
@click.argument (
' name '
)
@click.argument (
' size '
)
def ceph_volume_add ( pool , name , size ) :
"""
2019-06-21 09:22:24 -04:00
Add a new Ceph RBD volume with name NAME and size SIZE [ in human units , e . g . 1024 M , 20 G , etc . ] to pool POOL .
2019-06-19 00:12:44 -04:00
"""
zk_conn = pvc_common . startZKConnection ( zk_host )
retcode , retmsg = pvc_ceph . add_volume ( zk_conn , pool , name , size )
cleanup ( retcode , retmsg , zk_conn )
###############################################################################
2019-07-10 15:14:17 -04:00
# pvc storage ceph volume remove
2019-06-19 00:12:44 -04:00
###############################################################################
@click.command ( name = ' remove ' , short_help = ' Remove RBD volume. ' )
@click.argument (
' pool '
)
@click.argument (
' name '
)
2019-06-21 15:52:28 -04:00
@click.option (
' --yes ' , ' yes ' ,
is_flag = True , default = False ,
help = ' Pre-confirm the removal. '
)
def ceph_volume_remove ( pool , name , yes ) :
2019-06-19 00:12:44 -04:00
"""
Remove a Ceph RBD volume with name NAME from pool POOL .
"""
2019-06-21 15:52:28 -04:00
if not yes :
click . echo ( ' DANGER: This will completely remove volume {} from pool {} and all data contained in it. ' . format ( name , pool ) )
choice = input ( ' Are you sure you want to do this? (y/N) ' )
if choice != ' y ' and choice != ' Y ' :
exit ( 0 )
zk_conn = pvc_common . startZKConnection ( zk_host )
retcode , retmsg = pvc_ceph . remove_volume ( zk_conn , pool , name )
cleanup ( retcode , retmsg , zk_conn )
2019-06-19 00:12:44 -04:00
2019-07-26 14:24:22 -04:00
###############################################################################
# pvc storage ceph volume resize
###############################################################################
@click.command ( name = ' resize ' , short_help = ' Resize RBD volume. ' )
@click.argument (
' pool '
)
@click.argument (
' name '
)
@click.argument (
' size '
)
def ceph_volume_resize ( pool , name , size ) :
"""
Resize an existing Ceph RBD volume with name NAME in pool POOL to size SIZE [ in human units , e . g . 1024 M , 20 G , etc . ] .
"""
zk_conn = pvc_common . startZKConnection ( zk_host )
retcode , retmsg = pvc_ceph . resize_volume ( zk_conn , pool , name , size )
cleanup ( retcode , retmsg , zk_conn )
###############################################################################
# pvc storage ceph volume rename
###############################################################################
2019-07-26 14:53:27 -04:00
@click.command ( name = ' rename ' , short_help = ' Rename RBD volume. ' )
2019-07-26 14:24:22 -04:00
@click.argument (
' pool '
)
@click.argument (
' name '
)
@click.argument (
' new_name '
)
def ceph_volume_rename ( pool , name , new_name ) :
"""
Rename an existing Ceph RBD volume with name NAME in pool POOL to name NEW_NAME .
"""
zk_conn = pvc_common . startZKConnection ( zk_host )
retcode , retmsg = pvc_ceph . rename_volume ( zk_conn , pool , name , new_name )
cleanup ( retcode , retmsg , zk_conn )
2019-10-10 14:11:13 -04:00
###############################################################################
# pvc storage ceph volume clone
###############################################################################
@click.command ( name = ' rename ' , short_help = ' Clone RBD volume. ' )
@click.argument (
' pool '
)
@click.argument (
' name '
)
@click.argument (
' new_name '
)
def ceph_volume_clone ( pool , name , new_name ) :
"""
Clone a Ceph RBD volume with name NAME in pool POOL to name NEW_NAME in pool POOL .
"""
zk_conn = pvc_common . startZKConnection ( zk_host )
retcode , retmsg = pvc_ceph . clone_volume ( zk_conn , pool , name , new_name )
cleanup ( retcode , retmsg , zk_conn )
2019-06-19 00:12:44 -04:00
###############################################################################
2019-07-10 15:14:17 -04:00
# pvc storage ceph volume list
2019-06-19 00:12:44 -04:00
###############################################################################
@click.command ( name = ' list ' , short_help = ' List cluster RBD volumes. ' )
@click.argument (
' limit ' , default = None , required = False
)
2019-06-19 14:11:03 -04:00
@click.option (
' -p ' , ' --pool ' , ' pool ' ,
2019-07-05 13:57:15 -04:00
default = None , show_default = True ,
2019-06-19 14:11:03 -04:00
help = ' Show volumes from this pool only. '
)
def ceph_volume_list ( limit , pool ) :
2019-06-19 00:12:44 -04:00
"""
2019-06-19 15:22:44 -04:00
List all Ceph RBD volumes in the cluster ; optionally only match elements matching name regex LIMIT .
2019-06-19 00:12:44 -04:00
"""
zk_conn = pvc_common . startZKConnection ( zk_host )
2019-07-05 00:29:47 -04:00
retcode , retdata = pvc_ceph . get_list_volume ( zk_conn , pool , limit )
if retcode :
pvc_ceph . format_list_volume ( retdata )
retdata = ' '
cleanup ( retcode , retdata , zk_conn )
2019-06-19 00:12:44 -04:00
2019-06-19 00:23:14 -04:00
###############################################################################
2019-07-10 15:14:17 -04:00
# pvc storage ceph volume snapshot
2019-06-19 00:23:14 -04:00
###############################################################################
@click.group ( name = ' snapshot ' , short_help = ' Manage RBD volume snapshots in the PVC storage cluster. ' , context_settings = CONTEXT_SETTINGS )
def ceph_volume_snapshot ( ) :
"""
Manage the Ceph RBD volume snapshots of the PVC cluster .
"""
pass
2019-06-19 00:12:44 -04:00
###############################################################################
2019-07-10 15:14:17 -04:00
# pvc storage ceph volume snapshot add
2019-06-19 00:12:44 -04:00
###############################################################################
@click.command ( name = ' add ' , short_help = ' Add new RBD volume snapshot. ' )
@click.argument (
' pool '
)
@click.argument (
' volume '
)
@click.argument (
' name '
)
2019-06-19 00:23:14 -04:00
def ceph_volume_snapshot_add ( pool , volume , name ) :
2019-06-19 00:12:44 -04:00
"""
2019-07-28 23:00:35 -04:00
Add a snapshot with name NAME of Ceph RBD volume VOLUME in pool POOL .
2019-06-19 00:12:44 -04:00
"""
zk_conn = pvc_common . startZKConnection ( zk_host )
retcode , retmsg = pvc_ceph . add_snapshot ( zk_conn , pool , volume , name )
cleanup ( retcode , retmsg , zk_conn )
2019-07-28 23:00:35 -04:00
###############################################################################
# pvc storage ceph volume snapshot rename
###############################################################################
@click.command ( name = ' rename ' , short_help = ' Rename RBD volume snapshot. ' )
@click.argument (
' pool '
)
@click.argument (
' volume '
)
@click.argument (
' name '
)
@click.argument (
' new_name '
)
def ceph_volume_snapshot_rename ( pool , volume , name , new_name ) :
"""
Rename an existing Ceph RBD volume snapshot with name NAME to name NEW_NAME for volume VOLUME in pool POOL .
"""
zk_conn = pvc_common . startZKConnection ( zk_host )
retcode , retmsg = pvc_ceph . rename_snapshot ( zk_conn , pool , volume , name , new_name )
cleanup ( retcode , retmsg , zk_conn )
2019-06-19 00:12:44 -04:00
###############################################################################
2019-07-10 15:14:17 -04:00
# pvc storage ceph volume snapshot remove
2019-06-19 00:12:44 -04:00
###############################################################################
@click.command ( name = ' remove ' , short_help = ' Remove RBD volume snapshot. ' )
@click.argument (
' pool '
)
@click.argument (
' volume '
)
@click.argument (
' name '
)
2019-06-21 15:52:28 -04:00
@click.option (
' --yes ' , ' yes ' ,
is_flag = True , default = False ,
help = ' Pre-confirm the removal. '
)
def ceph_volume_snapshot_remove ( pool , volume , name , yes ) :
2019-06-19 00:12:44 -04:00
"""
2019-07-28 23:00:35 -04:00
Remove a Ceph RBD volume snapshot with name NAME from volume VOLUME in pool POOL .
2019-06-19 00:12:44 -04:00
"""
2019-06-21 15:52:28 -04:00
if not yes :
click . echo ( ' DANGER: This will completely remove snapshot {} from volume {} / {} and all data contained in it. ' . format ( name , pool , volume ) )
choice = input ( ' Are you sure you want to do this? (y/N) ' )
if choice != ' y ' and choice != ' Y ' :
exit ( 0 )
zk_conn = pvc_common . startZKConnection ( zk_host )
retcode , retmsg = pvc_ceph . remove_snapshot ( zk_conn , pool , volume , name )
cleanup ( retcode , retmsg , zk_conn )
2019-06-19 00:12:44 -04:00
###############################################################################
2019-07-10 15:14:17 -04:00
# pvc storage ceph volume snapshot list
2019-06-19 00:12:44 -04:00
###############################################################################
@click.command ( name = ' list ' , short_help = ' List cluster RBD volume shapshots. ' )
@click.argument (
2019-06-19 15:22:44 -04:00
' limit ' , default = None , required = False
2019-06-19 00:12:44 -04:00
)
2019-06-19 15:22:44 -04:00
@click.option (
' -p ' , ' --pool ' , ' pool ' ,
2019-07-05 13:57:15 -04:00
default = None , show_default = True ,
2019-06-19 15:22:44 -04:00
help = ' Show snapshots from this pool only. '
2019-06-19 00:12:44 -04:00
)
2019-06-19 15:22:44 -04:00
@click.option (
' -p ' , ' --volume ' , ' volume ' ,
2019-07-05 13:57:15 -04:00
default = None , show_default = True ,
2019-06-19 15:22:44 -04:00
help = ' Show snapshots from this volume only. '
2019-06-19 00:12:44 -04:00
)
2019-06-19 00:23:14 -04:00
def ceph_volume_snapshot_list ( pool , volume , limit ) :
2019-06-19 00:12:44 -04:00
"""
2019-06-19 15:22:44 -04:00
List all Ceph RBD volume snapshots ; optionally only match elements matching name regex LIMIT .
2019-06-19 00:12:44 -04:00
"""
zk_conn = pvc_common . startZKConnection ( zk_host )
2019-07-05 00:29:47 -04:00
retcode , retdata = pvc_ceph . get_list_snapshot ( zk_conn , pool , volume , limit )
if retcode :
pvc_ceph . format_list_snapshot ( retdata )
retdata = ' '
cleanup ( retcode , retdata , zk_conn )
2019-06-19 00:12:44 -04:00
2019-08-25 21:18:33 -04:00
###############################################################################
2019-10-22 11:23:12 -04:00
# pvc status
2019-08-25 21:18:33 -04:00
###############################################################################
2019-10-22 11:23:12 -04:00
@click.command ( name = ' status ' , short_help = ' Show current cluster status. ' )
@click.option (
' -f ' , ' --format ' , ' oformat ' , default = ' plain ' , show_default = True ,
type = click . Choice ( [ ' plain ' , ' json ' , ' json-pretty ' ] ) ,
help = ' Output format of cluster status information. '
)
def status_cluster ( oformat ) :
"""
Show basic information and health for the active PVC cluster .
"""
zk_conn = pvc_common . startZKConnection ( zk_host )
retcode , retdata = pvc_cluster . get_info ( zk_conn )
if retcode :
pvc_cluster . format_info ( retdata , oformat )
retdata = ' '
cleanup ( retcode , retdata , zk_conn )
2019-10-10 14:09:40 -04:00
2019-10-22 11:23:12 -04:00
###############################################################################
# pvc init
###############################################################################
2018-07-18 22:28:49 -04:00
@click.command ( name = ' init ' , short_help = ' Initialize a new cluster. ' )
2019-06-21 14:16:32 -04:00
@click.option (
' --yes ' , ' yes ' ,
2019-06-21 15:09:15 -04:00
is_flag = True , default = False ,
2019-06-21 14:16:32 -04:00
help = ' Pre-confirm the initialization. '
)
def init_cluster ( yes ) :
2018-06-06 01:07:59 -04:00
"""
2019-03-10 20:40:03 -04:00
Perform initialization of a new PVC cluster .
2018-06-06 01:07:59 -04:00
"""
2019-06-21 14:16:32 -04:00
if not yes :
click . echo ( ' DANGER: This will remove any existing cluster on these coordinators and create a new cluster. Any existing resources on the old cluster will be left abandoned. ' )
choice = input ( ' Are you sure you want to do this? (y/N) ' )
2019-06-21 15:52:28 -04:00
if choice != ' y ' and choice != ' Y ' :
2019-06-21 15:38:32 -04:00
exit ( 0 )
2019-07-06 19:00:57 -04:00
click . echo ( ' Initializing a new cluster with Zookeeper address " {} " . ' . format ( zk_host ) )
2019-08-20 09:19:56 -04:00
# Easter-egg
click . echo ( " Some music while we ' re Layin ' Pipe? https://youtu.be/sw8S_Kv89IU " )
2019-07-06 19:00:57 -04:00
# Open a Zookeeper connection
zk_conn = pvc_common . startZKConnection ( zk_host )
# Destroy the existing data
try :
zk_conn . delete ( ' /networks ' , recursive = True )
zk_conn . delete ( ' /domains ' , recursive = True )
zk_conn . delete ( ' /nodes ' , recursive = True )
zk_conn . delete ( ' /primary_node ' , recursive = True )
zk_conn . delete ( ' /ceph ' , recursive = True )
except :
pass
# Create the root keys
transaction = zk_conn . transaction ( )
transaction . create ( ' /nodes ' , ' ' . encode ( ' ascii ' ) )
transaction . create ( ' /primary_node ' , ' none ' . encode ( ' ascii ' ) )
transaction . create ( ' /domains ' , ' ' . encode ( ' ascii ' ) )
transaction . create ( ' /networks ' , ' ' . encode ( ' ascii ' ) )
transaction . create ( ' /ceph ' , ' ' . encode ( ' ascii ' ) )
transaction . create ( ' /ceph/osds ' , ' ' . encode ( ' ascii ' ) )
transaction . create ( ' /ceph/pools ' , ' ' . encode ( ' ascii ' ) )
transaction . create ( ' /ceph/volumes ' , ' ' . encode ( ' ascii ' ) )
transaction . create ( ' /ceph/snapshots ' , ' ' . encode ( ' ascii ' ) )
2019-08-07 13:42:01 -04:00
transaction . create ( ' /cmd ' , ' ' . encode ( ' ascii ' ) )
transaction . create ( ' /cmd/domains ' , ' ' . encode ( ' ascii ' ) )
transaction . create ( ' /cmd/ceph ' , ' ' . encode ( ' ascii ' ) )
2019-07-06 19:00:57 -04:00
transaction . commit ( )
# Close the Zookeeper connection
pvc_common . stopZKConnection ( zk_conn )
click . echo ( ' Successfully initialized new cluster. Any running PVC daemons will need to be restarted. ' )
2018-06-06 01:29:11 -04:00
2018-06-05 01:39:59 -04:00
2018-06-06 01:07:59 -04:00
###############################################################################
# pvc
###############################################################################
2018-06-05 01:39:59 -04:00
@click.group ( context_settings = CONTEXT_SETTINGS )
2018-06-06 01:07:59 -04:00
@click.option (
2018-10-25 11:54:05 -04:00
' -z ' , ' --zookeeper ' , ' _zk_host ' , envvar = ' PVC_ZOOKEEPER ' , default = None ,
2018-06-06 01:07:59 -04:00
help = ' Zookeeper connection string. '
)
def cli ( _zk_host ) :
"""
Parallel Virtual Cluster CLI management tool
2018-06-20 14:33:40 -04:00
2018-07-18 22:30:23 -04:00
Environment variables :
" PVC_ZOOKEEPER " : Set the cluster Zookeeper address instead of using " --zookeeper " .
2018-10-25 11:54:05 -04:00
2019-03-12 22:55:29 -04:00
If no PVC_ZOOKEEPER / - - zookeeper is specified , attempts to load coordinators list from / etc / pvc / pvcd . yaml .
2018-06-06 01:07:59 -04:00
"""
2019-03-12 22:55:29 -04:00
# If no zk_host was passed, try to read from /etc/pvc/pvcd.yaml; otherwise fail
2018-10-25 11:54:05 -04:00
if _zk_host is None :
try :
2019-03-12 22:55:29 -04:00
cfgfile = ' /etc/pvc/pvcd.yaml '
2019-03-12 23:11:10 -04:00
with open ( cfgfile ) as cfgf :
o_config = yaml . load ( cfgf )
2019-03-12 22:55:29 -04:00
_zk_host = o_config [ ' pvc ' ] [ ' cluster ' ] [ ' coordinators ' ]
2018-10-25 11:54:05 -04:00
except :
_zk_host = None
if _zk_host is None :
2019-03-12 22:55:29 -04:00
print ( ' ERROR: Must specify a PVC_ZOOKEEPER value or have a coordinator set configured in /etc/pvc/pvcd.yaml. ' )
2018-10-25 11:54:05 -04:00
exit ( 1 )
2018-06-06 01:20:09 -04:00
global zk_host
2018-06-06 01:07:59 -04:00
zk_host = _zk_host
2018-06-05 01:39:59 -04:00
#
# Click command tree
#
2018-10-14 02:01:35 -04:00
cli_node . add_command ( node_secondary )
cli_node . add_command ( node_primary )
2018-09-20 03:25:58 -04:00
cli_node . add_command ( node_flush )
cli_node . add_command ( node_ready )
cli_node . add_command ( node_unflush )
cli_node . add_command ( node_info )
cli_node . add_command ( node_list )
cli_vm . add_command ( vm_define )
2019-10-12 01:17:39 -04:00
cli_vm . add_command ( vm_meta )
2018-09-20 03:25:58 -04:00
cli_vm . add_command ( vm_modify )
cli_vm . add_command ( vm_undefine )
2019-06-27 11:19:48 -04:00
cli_vm . add_command ( vm_remove )
2019-03-12 21:09:54 -04:00
cli_vm . add_command ( vm_dump )
2018-09-20 03:25:58 -04:00
cli_vm . add_command ( vm_start )
cli_vm . add_command ( vm_restart )
cli_vm . add_command ( vm_shutdown )
cli_vm . add_command ( vm_stop )
2019-10-23 23:37:42 -04:00
cli_vm . add_command ( vm_disable )
2018-09-20 03:25:58 -04:00
cli_vm . add_command ( vm_move )
cli_vm . add_command ( vm_migrate )
cli_vm . add_command ( vm_unmigrate )
2019-08-07 13:42:01 -04:00
cli_vm . add_command ( vm_flush_locks )
2018-09-20 03:25:58 -04:00
cli_vm . add_command ( vm_info )
2019-04-11 19:06:06 -04:00
cli_vm . add_command ( vm_log )
2018-09-20 03:25:58 -04:00
cli_vm . add_command ( vm_list )
2018-09-21 23:43:30 -04:00
cli_network . add_command ( net_add )
2018-09-23 15:26:20 -04:00
cli_network . add_command ( net_modify )
2018-09-21 23:43:30 -04:00
cli_network . add_command ( net_remove )
cli_network . add_command ( net_info )
cli_network . add_command ( net_list )
2018-09-28 20:31:56 -04:00
cli_network . add_command ( net_dhcp )
cli_network . add_command ( net_acl )
net_dhcp . add_command ( net_dhcp_list )
2018-10-03 19:23:46 -04:00
net_dhcp . add_command ( net_dhcp_static )
net_dhcp_static . add_command ( net_dhcp_static_add )
net_dhcp_static . add_command ( net_dhcp_static_remove )
net_dhcp_static . add_command ( net_dhcp_static_list )
2018-09-21 23:43:30 -04:00
2018-10-17 00:23:27 -04:00
net_acl . add_command ( net_acl_add )
net_acl . add_command ( net_acl_remove )
net_acl . add_command ( net_acl_list )
2018-10-28 22:15:25 -04:00
ceph_osd . add_command ( ceph_osd_add )
2018-10-29 17:51:08 -04:00
ceph_osd . add_command ( ceph_osd_remove )
2018-11-01 22:00:59 -04:00
ceph_osd . add_command ( ceph_osd_in )
ceph_osd . add_command ( ceph_osd_out )
ceph_osd . add_command ( ceph_osd_set )
ceph_osd . add_command ( ceph_osd_unset )
2018-10-30 09:17:32 -04:00
ceph_osd . add_command ( ceph_osd_list )
2018-10-27 18:11:58 -04:00
2018-10-31 23:38:17 -04:00
ceph_pool . add_command ( ceph_pool_add )
ceph_pool . add_command ( ceph_pool_remove )
ceph_pool . add_command ( ceph_pool_list )
2018-10-27 18:11:58 -04:00
2019-06-19 00:12:44 -04:00
ceph_volume . add_command ( ceph_volume_add )
2019-07-26 14:24:22 -04:00
ceph_volume . add_command ( ceph_volume_resize )
ceph_volume . add_command ( ceph_volume_rename )
2019-06-19 00:12:44 -04:00
ceph_volume . add_command ( ceph_volume_remove )
ceph_volume . add_command ( ceph_volume_list )
ceph_volume . add_command ( ceph_volume_snapshot )
ceph_volume_snapshot . add_command ( ceph_volume_snapshot_add )
2019-07-28 23:00:35 -04:00
ceph_volume_snapshot . add_command ( ceph_volume_snapshot_rename )
2019-06-19 00:12:44 -04:00
ceph_volume_snapshot . add_command ( ceph_volume_snapshot_remove )
ceph_volume_snapshot . add_command ( ceph_volume_snapshot_list )
2018-10-27 18:11:58 -04:00
cli_ceph . add_command ( ceph_status )
2019-07-08 10:56:33 -04:00
cli_ceph . add_command ( ceph_radosdf )
2018-10-27 18:11:58 -04:00
cli_ceph . add_command ( ceph_osd )
cli_ceph . add_command ( ceph_pool )
2019-06-19 00:12:44 -04:00
cli_ceph . add_command ( ceph_volume )
2018-10-27 18:11:58 -04:00
2019-07-10 15:14:17 -04:00
cli_storage . add_command ( cli_ceph )
2018-09-20 03:25:58 -04:00
cli . add_command ( cli_node )
cli . add_command ( cli_vm )
2018-09-21 23:43:30 -04:00
cli . add_command ( cli_network )
2019-07-10 15:14:17 -04:00
cli . add_command ( cli_storage )
2019-10-22 11:23:12 -04:00
cli . add_command ( status_cluster )
2018-06-06 01:20:09 -04:00
cli . add_command ( init_cluster )
2018-06-05 01:39:59 -04:00
#
# Main entry point
#
def main ( ) :
return cli ( obj = { } )
if __name__ == ' __main__ ' :
main ( )
2018-06-14 11:57:36 -04:00