From 8e7d432f1be0af88e4dec217838ebd09d2afb6a0 Mon Sep 17 00:00:00 2001 From: "Daniel P. Smith" Date: Wed, 6 Oct 2021 14:26:03 -0400 Subject: [PATCH 01/18] sync-cmd: adding ability to create vms This adds the ability to create vms via the `unrestricted_create_vm_with_template_and_json` method of xenmgr's unrestricted interface. This will create a vm based on one of the vm templates stored in Dom0 while also applying the contents of a JSON file as the vm's configuration. The JSON file must follow the same conventions as a vm config file stored in /config/vms. Signed-off-by: Daniel P. Smith --- pysynchronizer/cmd.py | 20 ++++++++++++++++---- pysynchronizer/objects.py | 15 +++++++++++++++ 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/pysynchronizer/cmd.py b/pysynchronizer/cmd.py index 2c5494a..e952e91 100644 --- a/pysynchronizer/cmd.py +++ b/pysynchronizer/cmd.py @@ -21,7 +21,7 @@ from .errors import ConnectionError from .objects import XenMgr, VM -from .utils import column_print +from .utils import column_print, dbus_path_to_uuid class BaseCmd(Cmd): def __init__(self): @@ -87,10 +87,22 @@ def do_vms(self, arg_str): column_print(rows) print('') - # TODO: implement def do_create_vm(self ,arg_str): - """Not Implemented""" - print("Not Implemented\n") + """Usage: create_vm {template name} [path to json]""" + + tmplate, json_file = arg_str.split(None, 1) + + json = "" + try: + with open(json_file, 'r') as f: + json = f.read() + except OSError: + print(' ERR: failure reading json file %s' % json_file) + return + + path = self.xenmgr.create_vm(tmplate, json) + + print(dbus_path_to_uuid(path)) def help_delete_vm(self): print('Usage: delete_vm [uuid|name]\n') diff --git a/pysynchronizer/objects.py b/pysynchronizer/objects.py index 9974c09..7ba239f 100644 --- a/pysynchronizer/objects.py +++ b/pysynchronizer/objects.py @@ -36,6 +36,12 @@ def get_current_release_and_build(self): build_info = self.host.get_property('build-info') return build_info['release'], build_info['build'] + # NB: RPC Proxy rules must be adjusted to allow + def templates(self): + """Returns a list of templates""" + + return self.xenmgr.list_templates() + def vm_by_name(self): """Returns a dictionary of name:uuid pairs""" d = {} @@ -71,6 +77,15 @@ def find_vm(self, ref): return None + def create_vm(self, template, json): + """Creates a VM from template using JSON data returning object path""" + try: + unrestricted = OXTDBusApi.open_xenmgr_unrestricted() + except Exception as err: + raise ConnectionError('Failed to connect to XenMgr unrestricted service') from err + + return str(unrestricted.unrestricted_create_vm_with_template_and_json(template, json)) + def upgrade(self, url): """Takes a url, downloads it, and moves it for the upgrade manager to find""" storage = Storage() From 2279ed73a8cafda627daff172d1c3ca63e30af90 Mon Sep 17 00:00:00 2001 From: "Daniel P. Smith" Date: Mon, 18 Oct 2021 15:01:01 -0400 Subject: [PATCH 02/18] sync-cmd: adding ability to manage usb policy This commit adds the ability to list, inspect (aka show), and add USB policy rules to the USB Daemon. Signed-off-by: Daniel P. Smith --- pysynchronizer/cmd.py | 71 ++++++++++++++++- pysynchronizer/objects.py | 159 ++++++++++++++++++++++++++++++++++++- pysynchronizer/oxt_dbus.py | 11 +++ 3 files changed, 239 insertions(+), 2 deletions(-) diff --git a/pysynchronizer/cmd.py b/pysynchronizer/cmd.py index e952e91..20a79bc 100644 --- a/pysynchronizer/cmd.py +++ b/pysynchronizer/cmd.py @@ -16,11 +16,13 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # +import shlex + from cmd import Cmd from os.path import split from .errors import ConnectionError -from .objects import XenMgr, VM +from .objects import XenMgr, VM, Usb, UsbPolicyRule from .utils import column_print, dbus_path_to_uuid class BaseCmd(Cmd): @@ -66,6 +68,14 @@ def do_vm(self, arg_str): except Exception as err: print('Unexpected exception:\n\t%s\n' % err) + def do_usb(self, arg_str): + try: + UsbCmd().run(arg_str) + except ConnectionError as err: + print('Connection failed:\n\t%s\n' % err) + except Exception as err: + print('Unexpected exception:\n\t%s\n' % err) + class XenMgrCmd(BaseCmd): def __init__(self): super().__init__() @@ -265,6 +275,65 @@ def do_disk(self, arg_str): else: print('Failed to replace disk\n') +class UsbCmd(BaseCmd): + def __init__(self): + super().__init__() + + self.prompt = "usb> " + self.usb = Usb() + + def do_list(self, arg_str): + rows = [ [ + "rule id", + "description", + "vm uuid", + ] ] + + for rule in self.usb.policy_get_rules(): + rows.append(rule.summary_array()) + + column_print(rows) + print('') + + def help_show(self): + print('Usage: show [rule # | all]\n') + print('Show the definition for the rule or for all rules') + + def do_show(self, arg_str): + args = arg_str.split() + if len(args) < 1: + self.help_show() + return + + if args[0].isdigit(): + rule_id = int(args[0]) + rule = self.usb.policy_get_rule(rule_id) + rule.show('', 0) + return + + if args[0] != "all": + self.help_show() + return + + for rule in self.usb.policy_get_rules(): + rule.show('', 0) + print('') + + def do_set(self, arg_str): + arg_sep = '=' + rule = UsbPolicyRule(None) # get an empty rule + + args = shlex.split(arg_str) + for arg in args: + key, value = arg.split(arg_sep) + + try: + rule.set(key, value) + except Exception as err: + print("Error: %s" % err) + return + + self.usb.policy_set_rule(rule) if __name__ == '__main__': import sys diff --git a/pysynchronizer/objects.py b/pysynchronizer/objects.py index 7ba239f..1ee302a 100644 --- a/pysynchronizer/objects.py +++ b/pysynchronizer/objects.py @@ -19,7 +19,7 @@ import os.path from .utils import is_valid_uuid, dbus_path_to_uuid, uuid_to_dbus_path -from .errors import ConnectionError, ConfigError +from .errors import Error, ConnectionError, ConfigError from .storage import Storage from .oxt_dbus import OXTDBusApi @@ -204,3 +204,160 @@ def replace(self, url): return storage.download_disk(self.name(), url) except: return None + +class Usb: + def __init__(self): + try: + self.usb = OXTDBusApi.open_usb() + except Exception as err: + raise ConnectionError('Failed to connect to USB service') from err + + # policy_set_rule: Set or create a specific USB rule + # + # rule_id(int): ID of the rule. If a rule exists with the ID, it will be replaced. + # command(string): Command string of {allow, always, default, deny} + # description(string): Description of the policy rule + # vendor_id(string): USB vendor ID as headecimal, parsed by strtol (e.g. 8086) + # device_id(string): USB product ID as hexadecimal, parsed by strtol (e.g. 1a2c) + # serial_number(string): Serial number of the device, or an empty string to match any + # sysattrs(dictionary): Dict of String:String sysattributes + # udev_properties(dictionary): Dict of String:String udev properties + # vm_uuid(string): VM UUID, or an empty string to match any VM + def policy_set_rule(self, rule): + return self.usb.policy_set_rule(rule.idx, rule.cmd, rule.desc, rule.vid, rule.pid, rule.serial, rule.sysattrs, rule.udev, rule.vm) + + # policy_set_rule_advanced: Set or create a specific USB rule, an advanced interface wrapper around policy_set_rule + # + # rule_id(int): ID of the rule. If a rule exists with the ID, it will be replaced. + # command(string): Command string of {allow, always, default, deny} + # description(string): Description of the policy rule + # sysattrs(dictionary): Dict of String:String sysattributes + # udev_properties(dictionary): Dict of String:String udev properties + # vm_uuid(string): VM UUID, or an empty string to match any VM + def policy_set_rule_advanced(self, rule): + return self.usb.policy_set_rule_advanced(rule.idx, rule.cmd, rule.desc, rule.sysattrs, rule.udev, rule.vm) + + # policy_set_rule: Set or create a specific USB rule, interface wrapper around policy_set_rule + # + # rule_id(int): ID of the rule. If a rule exists with the ID, it will be replaced. + # command(string): Command string of {allow, always, default, deny} + # description(string): Description of the policy rule + # vendor_id(string): USB vendor ID as headecimal, parsed by strtol (e.g. 8086) + # device_id(string): USB product ID as hexadecimal, parsed by strtol (e.g. 1a2c) + # serial_number(string): Serial number of the device, or an empty string to match any + def policy_set_rule_basic(self, rule): + return self.usb.policy_set_rule_basic(rule.idx, rule.cmd, rule.desc, rule.vid, rule.pid, rule.serial) + + # policy_get_rules: Get a set of all USB rules + # The set of rules in the format as an array of structs of: + # * int: Rule ID + # * string: Command + # * string: Description + # * string: Vendor ID as a String interpretable by strtol (e.g. 8086). An empty string or 0 indicates to match any device. + # * string: Product ID as a String interpretable by strtol (e.g. 8086). An empty string or 0 indicates to match any device. + # * string: Serial number of device. An empty string indicates to ignore serial number (match any). + # * [string]string: Dict of String:String sysattibutes + # * [string]string: Dict of String:String udev properties + # * string: VM UUID, or an empty string to match any VM + def policy_get_rules(self): + rules = [] + for rule in self.usb.policy_get_rules(): + rules.append(UsbPolicyRule(rule)) + + return rules + + # policy_get_rule: Get a specific USB rule + # + # rule_id(int): Index position of the rule to get + # + # returns: + # string: Command string of {allow, always, default, deny} + # string: Description of the policy rule + # string: USB vendor ID as hexadecimal, parsed by strtol (e.g. 8086) + # string: USB product ID as hexadecimal, parsed by strtol (e.g. 1a2c) + # string: Serial number of the device, or an empty string to match any + # dictionary: Dict of String:String sysattributes + # dictionary: Dict of String:String udev properties + # string: VM UUID, or an empty string to match any VM + def policy_get_rule(self, rule_id): + values = [rule_id] + + values.extend(self.usb.policy_get_rule(rule_id)) + + return UsbPolicyRule(values) + +class UsbPolicyRule: + + def __init__(self, values): + if values == None: + self.idx = -1 + self.cmd = "" + self.desc = "" + self.vid = "" + self.pid = "" + self.serial = "" + self.sysattrs = {} + self.udev = {} + self.vm = "" + return + + if len(values) != 9: + raise Error("Incorrect number of fields passed to create UsbPolicyRule") + + self.idx, self.cmd, self.desc, self.vid, self.pid, self.serial, self.sysattrs, self.udev, self.vm = values + + def __repr__(self): + return "idx:%d cmd:%s desc:%s vid:%s pid:%s serial:%s sysattrs:%s udev:%s self.vm: %s" % \ + (self.idx, self.cmd, self.desc, self.vid, self.pid, self.serial, self.sysattrs, self.udev, self.vm) + + def summary_array(self): + return [ self.idx, self.desc, self.vm ] + + # indent: indent char string + # count: number of indent instances to prepend + def show(self, indent, count): + if indent == None or indent == '': + indent = " " + + if type(count) != int: + count = 0 + + prepend = indent * count + + print("%sRule Index: %s" % (prepend, self.idx)) + print("%sCommand: %s" % (prepend, self.cmd)) + print("%sDescription: %s" % (prepend, self.desc)) + print("%sVendor Id: %s" % (prepend, self.vid)) + print("%sProduct Id: %s" % (prepend, self.pid)) + print("%sSerial Num: %s" % (prepend, self.serial)) + print("%sSystem Attrs:" % prepend) + for k,v in self.sysattrs.items(): + print("%s%s: %s" % (prepend + indent, k, v)) + print("%sUdev Props:" % prepend) + for k,v in self.udev.items(): + print("%s%s: %s" % (prepend + indent, k, v)) + print("%sVM UUID: %s" % (prepend, self.vm)) + + def set(self, key, value): + dict_sep = ':' + + # Idx is an integer + if key in ('idx'): + self.__dict__[key] = int(value) + return + + # Handle all the keys that have string values + if key in ('cmd', 'desc', 'vid', 'pid', 'serial', 'vm'): + self.__dict__[key] = value + return + + # Handle keys that are dictionaries + if key in ('sysattrs', 'udev'): + if not key in self.__dict__: + self.__dict__[key] = {} + + k, v = value.split(dict_sep) + self.__dict__[key][k] = v + return + + raise Error("Unknown USB Policy Rule attribute: %s", key) diff --git a/pysynchronizer/oxt_dbus.py b/pysynchronizer/oxt_dbus.py index 2e60fce..9ef6e88 100644 --- a/pysynchronizer/oxt_dbus.py +++ b/pysynchronizer/oxt_dbus.py @@ -22,6 +22,7 @@ # DBus Services XENMGR_SERVICE = 'com.citrix.xenclient.xenmgr' DBD_SERVICE = 'com.citrix.xenclient.db' +USB_SERVICE = 'com.citrix.xenclient.usbdaemon' # DBus Interfaces XENMGR_INTF = 'com.citrix.xenclient.xenmgr' @@ -31,6 +32,7 @@ DISK_INTF = 'com.citrix.xenclient.vmdisk' INPUT_INTF = 'com.citrix.xenclient.input' DB_INTF = 'com.citrix.xenclient.db' +USB_INTF = 'com.citrix.xenclient.usbdaemon' class ServiceObject: def __init__(self, service, intf, obj_path): @@ -114,3 +116,12 @@ def open_db(): except: obj = None return obj + + @staticmethod + def open_usb(): + """Return a dbus proxy for the database (i.e. domstore) interface""" + try: + obj = ServiceObject(USB_SERVICE, USB_INTF, '/') + except: + obj = None + return obj From 028141c3fd5bfc9f016061e8811dd91063b08942 Mon Sep 17 00:00:00 2001 From: "Daniel P. Smith" Date: Tue, 19 Oct 2021 13:44:11 -0400 Subject: [PATCH 03/18] sync-cmd: add access to network daemon Signed-off-by: Daniel P. Smith --- pysynchronizer/cmd.py | 50 +++++++++++++++++++++++++++++++++++++- pysynchronizer/objects.py | 40 ++++++++++++++++++++++++++++++ pysynchronizer/oxt_dbus.py | 11 +++++++++ 3 files changed, 100 insertions(+), 1 deletion(-) diff --git a/pysynchronizer/cmd.py b/pysynchronizer/cmd.py index 20a79bc..2e772d5 100644 --- a/pysynchronizer/cmd.py +++ b/pysynchronizer/cmd.py @@ -22,7 +22,7 @@ from os.path import split from .errors import ConnectionError -from .objects import XenMgr, VM, Usb, UsbPolicyRule +from .objects import XenMgr, VM, Usb, UsbPolicyRule, Net from .utils import column_print, dbus_path_to_uuid class BaseCmd(Cmd): @@ -76,6 +76,14 @@ def do_usb(self, arg_str): except Exception as err: print('Unexpected exception:\n\t%s\n' % err) + def do_net(self, arg_str): + try: + NetCmd().run(arg_str) + except ConnectionError as err: + print('Connection failed:\n\t%s\n' % err) + except Exception as err: + print('Unexpected exception:\n\t%s\n' % err) + class XenMgrCmd(BaseCmd): def __init__(self): super().__init__() @@ -335,6 +343,46 @@ def do_set(self, arg_str): self.usb.policy_set_rule(rule) +class NetCmd(BaseCmd): + def __init__(self): + super().__init__() + + self.prompt = "net> " + self.net = Net() + + def do_list(self, arg_str): + rows = [ [ + "object", + "label", + "mac", + "driver", + "backend", + ] ] + + for network in self.net.list(): + row = [network['object']] + row.append(network['label']) + row.append(network['mac']) + row.append(network['driver']) + row.append(network['backend_vm']) + + rows.append(row) + + column_print(rows) + print('') + + def help_mac_addr(self): + print('Usage: mac_addr network_object\n') + print('Retrieve the mac address for the given network') + + def do_mac_addr(self, arg_str): + args = arg_str.split() + if len(args) != 1: + self.help_mac_addr() + return + + print('%s\n' % self.net.get_mac(args[0])) + if __name__ == '__main__': import sys diff --git a/pysynchronizer/objects.py b/pysynchronizer/objects.py index 1ee302a..03e364b 100644 --- a/pysynchronizer/objects.py +++ b/pysynchronizer/objects.py @@ -361,3 +361,43 @@ def set(self, key, value): return raise Error("Unknown USB Policy Rule attribute: %s", key) + +class Net: + def __init__(self): + try: + self.net = OXTDBusApi.open_net() + except Exception as err: + raise ConnectionError('Failed to connect to Network service') from err + + # create_network: Creates network using configuration. + # kind(string) + # id(int) + # config(string) + # + # returns: + # network(string) + def create_network(self, kind, id, config): + return self.net.create_network(kind, id, config) + + # list: Lists networks. + # + # returns: + # networks(array of dictionaries) + def list(self): + return self.net.list() + + def list_by_type(self, kind): + networks = [] + + for network in self.list(): + if str(network['type']) == kind: + networks.append(network) + + return networks + + def get_mac(self, obj): + for net in self.list(): + if str(net['object']) == obj: + return str(net['mac']) + + return None diff --git a/pysynchronizer/oxt_dbus.py b/pysynchronizer/oxt_dbus.py index 9ef6e88..56707fe 100644 --- a/pysynchronizer/oxt_dbus.py +++ b/pysynchronizer/oxt_dbus.py @@ -23,6 +23,7 @@ XENMGR_SERVICE = 'com.citrix.xenclient.xenmgr' DBD_SERVICE = 'com.citrix.xenclient.db' USB_SERVICE = 'com.citrix.xenclient.usbdaemon' +NET_SERVICE = 'com.citrix.xenclient.networkdaemon' # DBus Interfaces XENMGR_INTF = 'com.citrix.xenclient.xenmgr' @@ -33,6 +34,7 @@ INPUT_INTF = 'com.citrix.xenclient.input' DB_INTF = 'com.citrix.xenclient.db' USB_INTF = 'com.citrix.xenclient.usbdaemon' +NET_INTF = 'com.citrix.xenclient.networkdaemon' class ServiceObject: def __init__(self, service, intf, obj_path): @@ -125,3 +127,12 @@ def open_usb(): except: obj = None return obj + + @staticmethod + def open_net(): + """Return a dbus proxy for the network daemon interface""" + try: + obj = ServiceObject(NET_SERVICE, NET_INTF, '/') + except: + obj = None + return obj From de98e60f9b5a7099076ac560a44f710dcbd28bc3 Mon Sep 17 00:00:00 2001 From: "Daniel P. Smith" Date: Tue, 19 Oct 2021 15:04:17 -0400 Subject: [PATCH 04/18] sync-cmd: add ability to get and set xenmgr config Signed-off-by: Daniel P. Smith --- pysynchronizer/cmd.py | 20 ++++++++++++++++++++ pysynchronizer/objects.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/pysynchronizer/cmd.py b/pysynchronizer/cmd.py index 2e772d5..07ea341 100644 --- a/pysynchronizer/cmd.py +++ b/pysynchronizer/cmd.py @@ -91,6 +91,26 @@ def __init__(self): self.prompt = "xemmgr> " self.xenmgr = XenMgr() + def help_config(self): + print('Usage: config {command}\n') + print('Available commands:') + print(' get {property}: get config property\n') + print(' set {property}: get config property\n') + + def do_config(self, arg_str): + args = arg_str.split() + if len(args) < 2: + self.help_config() + return + + comm, args = args[0], args[1:] + + if comm == 'get': + print('%s\n' % self.xenmgr.config_get(args[0])) + + if comm == 'set': + self.xenmgr.config_set(args[0], args[1]) + def do_vms(self, arg_str): """Usage: vms\n\nList all VMs\n """ rows = [ [ diff --git a/pysynchronizer/objects.py b/pysynchronizer/objects.py index 03e364b..5ef0690 100644 --- a/pysynchronizer/objects.py +++ b/pysynchronizer/objects.py @@ -16,6 +16,7 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # +import dbus import os.path from .utils import is_valid_uuid, dbus_path_to_uuid, uuid_to_dbus_path @@ -36,6 +37,33 @@ def get_current_release_and_build(self): build_info = self.host.get_property('build-info') return build_info['release'], build_info['build'] + def config_get(self, key): + value = self.xenmgr.propi.Get('com.citrix.xenclient.xenmgr.config', key) + + if isinstance(value, dbus.Boolean): + return bool(value) + + if isinstance(value, dbus.Int32): + return int(value) + + if isinstance(value, dbus.String): + return str(value) + + return value + + def config_set(self, key, value): + v = self.config_get(key) + + if isinstance(v, bool): + if value.lower() == "true": + value = True + else: + value = False + elif isinstance(v, int): + value = int(value) + + return str(self.xenmgr.propi.Set('com.citrix.xenclient.xenmgr.config', key, value)) + # NB: RPC Proxy rules must be adjusted to allow def templates(self): """Returns a list of templates""" From c8afc564f5d37133374949034549726e45af9e34 Mon Sep 17 00:00:00 2001 From: "Daniel P. Smith" Date: Mon, 8 Nov 2021 13:54:36 -0500 Subject: [PATCH 05/18] sync-cmd: adding argo firewall support Signed-off-by: Daniel P. Smith --- pysynchronizer/cmd.py | 38 ++++++++++++++++++++++++++++++++++++++ pysynchronizer/objects.py | 20 ++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/pysynchronizer/cmd.py b/pysynchronizer/cmd.py index 07ea341..7670c04 100644 --- a/pysynchronizer/cmd.py +++ b/pysynchronizer/cmd.py @@ -239,6 +239,44 @@ def do_domstore(self, arg_str): print('Unknown domstore command: %s\n' % cmd) + def help_argo_firewall(self): + print('Usage: argo_firewall list|[add|delete rule]\n') + print('\tlist: List Argo firewall rules\n') + print('\tadd|delete rule: Add/delete rule to Argo firewall\n') + + def do_argo_firewall(self, arg_str): + args = arg_str.split() + if not args: + self.help_argo_firewall() + return + + cmd, args = args[0], args[1:] + + if cmd == "list": + col = [["Argo Rules"]] + for rule in self.vm.list_argo_firewall_rules(): + col.append([rule]) + column_print(col) + return + + if cmd == "add": + if len(args) == 0: + print('Usage: argo_firewall add rule\n') + return + rule = " ".join(args).replace('"', '').replace("'", "") + print(self.vm.add_argo_firewall_rule(rule)) + return + + if cmd == "delete": + if len(args) == 0: + print('Usage: argo_firewall delete rule\n') + return + rule = " ".join(args).replace('"', '').replace("'", "") + print(self.vm.delete_argo_firewall_rule(rule)) + return + + print('Unknown argo_firewall command: %s\n' % cmd) + def do_disks(self, arg_str): """Usage: disks\n\nList all disks associated with selected VM\n """ if self.vm is None: diff --git a/pysynchronizer/objects.py b/pysynchronizer/objects.py index 5ef0690..8244200 100644 --- a/pysynchronizer/objects.py +++ b/pysynchronizer/objects.py @@ -181,6 +181,26 @@ def domstore_set(self, key, value): except: return "" + def list_argo_firewall_rules(self): + """List Argo firewall rules""" + return self.proxy_object.list_argo_firewall_rules() + + def add_argo_firewall_rule(self, rule): + """Add firewall rule to Argo firewall""" + try: + self.proxy_object.add_argo_firewall_rule(rule) + return rule + except: + return "" + + def delete_argo_firewall_rule(self, rule): + """Delete firewall rule to Argo firewall""" + try: + self.proxy_object.delete_argo_firewall_rule(rule) + return rule + except: + return "" + def disks(self): """Retrieve a list of VMDisk objects of the disk associate with the VM""" disks = [] From c70bf2baab62fbd2ba66ff6aab517d0594a13e9a Mon Sep 17 00:00:00 2001 From: "Daniel P. Smith" Date: Tue, 9 Nov 2021 12:43:19 -0500 Subject: [PATCH 06/18] sync-cmd: add create to net cmd This adds the a create command to the net command to allow the creation of networks. Signed-off-by: Daniel P. Smith --- pysynchronizer/cmd.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/pysynchronizer/cmd.py b/pysynchronizer/cmd.py index 7670c04..e0806f7 100644 --- a/pysynchronizer/cmd.py +++ b/pysynchronizer/cmd.py @@ -429,6 +429,23 @@ def do_list(self, arg_str): column_print(rows) print('') + def help_create(self): + print('Usage: create network_id backing_uuid mac_address\n') + print('Create network with a backing domain and mac address') + + def do_create(self, arg_str): + args = arg_str.split() + if len(args) != 1: + self.help_create() + return + + net_num, uuid, mac_addr = args[0], args[1], args[2] + config = "uuid=%s,%s,,,," % (uuid, mac_addr) + + print("Created:") + for net_type in ['wired', 'internal', 'any']: + print("\t%s" % self.net.create_network(net_type, net_num, config)) + def help_mac_addr(self): print('Usage: mac_addr network_object\n') print('Retrieve the mac address for the given network') From 80bbdb35d4cde91fa5406f1c040cd4f7302df93f Mon Sep 17 00:00:00 2001 From: Jason Andryuk Date: Mon, 5 Jun 2023 07:11:00 -0400 Subject: [PATCH 07/18] sync-cmd: return release and build info Print it so remote management can decide if an OTA is needed. Signed-off-by: Jason Andryuk --- pysynchronizer/cmd.py | 12 ++++++++++++ pysynchronizer/objects.py | 4 ++++ 2 files changed, 16 insertions(+) diff --git a/pysynchronizer/cmd.py b/pysynchronizer/cmd.py index e0806f7..cd2b91c 100644 --- a/pysynchronizer/cmd.py +++ b/pysynchronizer/cmd.py @@ -51,6 +51,9 @@ def do_xenmgr(self, arg_str): except Exception as err: print('Unexpected exception:\n\t%s\n' % err) + def do_upgrade(self, arg_str): + self.do_xenmgr("upgrade " + arg_str) + def do_vm(self, arg_str): args = arg_str.split() @@ -91,6 +94,15 @@ def __init__(self): self.prompt = "xemmgr> " self.xenmgr = XenMgr() + def help_release(self): + print('Usage: release\n') + print('Prints Software build information') + + def do_release(self, arg_str): + release = self.xenmgr.get_release_and_build() + for key in release.keys(): + print("%s: %s" % (key, release[key])) + def help_config(self): print('Usage: config {command}\n') print('Available commands:') diff --git a/pysynchronizer/objects.py b/pysynchronizer/objects.py index 8244200..e94cddd 100644 --- a/pysynchronizer/objects.py +++ b/pysynchronizer/objects.py @@ -37,6 +37,10 @@ def get_current_release_and_build(self): build_info = self.host.get_property('build-info') return build_info['release'], build_info['build'] + def get_release_and_build(self): + """Get current XC release and build number from xenmgr""" + return self.host.get_property('build-info') + def config_get(self, key): value = self.xenmgr.propi.Get('com.citrix.xenclient.xenmgr.config', key) From 1e1df413f582c2450cbae2ec40dd0be1a7c270a6 Mon Sep 17 00:00:00 2001 From: Jason Andryuk Date: Wed, 9 Feb 2022 14:55:23 -0500 Subject: [PATCH 08/18] sync-cmd: fix column_print A bug in column_print resulted in `TypeError: object of type 'dbus.Int32' has no len()`. Change col to a string so we can use string operations. Signed-off-by: Jason Andryuk --- pysynchronizer/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pysynchronizer/utils.py b/pysynchronizer/utils.py index 393f6d5..4c56082 100644 --- a/pysynchronizer/utils.py +++ b/pysynchronizer/utils.py @@ -19,10 +19,10 @@ def column_print(rows): for idx, col in enumerate(row): if idx == len(col_width): col_width.append(0) - col_width[idx] = max(col_width[idx], len(col) + 2) + col_width[idx] = max(col_width[idx], len(str(col)) + 2) for row in rows: - print("".join(col.ljust(col_width[idx]) for idx, col in enumerate(row))) + print("".join(str(col).ljust(col_width[idx]) for idx, col in enumerate(row))) def dbus_path_to_uuid(path): return path.rsplit('/',1)[1].replace('_','-') From 4f9baf85242a2c477ea14c5394d5f6ce207a5608 Mon Sep 17 00:00:00 2001 From: Jason Andryuk Date: Thu, 10 Feb 2022 15:30:02 -0500 Subject: [PATCH 09/18] sync-cmd: add "usb remove #" Allow deleting USB rules. Signed-off-by: Jason Andryuk --- pysynchronizer/cmd.py | 7 +++++++ pysynchronizer/objects.py | 6 ++++++ 2 files changed, 13 insertions(+) diff --git a/pysynchronizer/cmd.py b/pysynchronizer/cmd.py index cd2b91c..8cf7daf 100644 --- a/pysynchronizer/cmd.py +++ b/pysynchronizer/cmd.py @@ -413,6 +413,13 @@ def do_set(self, arg_str): self.usb.policy_set_rule(rule) + def help_remove(self): + print('Usage: remove [rule #]\n') + print('Remove the given rule #') + + def do_remove(self, arg_str): + self.usb.policy_remove_rule(int(arg_str)) + class NetCmd(BaseCmd): def __init__(self): super().__init__() diff --git a/pysynchronizer/objects.py b/pysynchronizer/objects.py index e94cddd..600691c 100644 --- a/pysynchronizer/objects.py +++ b/pysynchronizer/objects.py @@ -338,6 +338,12 @@ def policy_get_rule(self, rule_id): return UsbPolicyRule(values) + # policy_remove_rule: Remove a specific USB rule + # + # rule_id(int): ID of the rule to remove + def policy_remove_rule(self, rule_id): + return self.usb.policy_remove_rule(rule_id) + class UsbPolicyRule: def __init__(self, values): From fd27253398d7cca811e3217453e9c274279e7ac9 Mon Sep 17 00:00:00 2001 From: Jason Andryuk Date: Fri, 11 Feb 2022 11:21:53 -0500 Subject: [PATCH 10/18] sync-cmd: handle ctrl-d Add ctrl-D support by implementing do_EOF. It exits to one level up when called, which exits the program from the top level. Signed-off-by: Jason Andryuk --- pysynchronizer/cmd.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pysynchronizer/cmd.py b/pysynchronizer/cmd.py index 8cf7daf..0a7dbe2 100644 --- a/pysynchronizer/cmd.py +++ b/pysynchronizer/cmd.py @@ -38,6 +38,10 @@ def run(self, cmd_str=""): def do_exit(self, args): return -1 + def do_EOF(self, args): + print() + return True + class SyncCmd(BaseCmd): def __init__(self, cmd_str=""): super().__init__() From bd5f89318d5a9d12abefaa19d64eb04156d9b449 Mon Sep 17 00:00:00 2001 From: Jason Andryuk Date: Fri, 11 Feb 2022 11:23:02 -0500 Subject: [PATCH 11/18] sync-cmd: handle names with spaces VM Names can have spaces, so try to support that. The xenmgr commands can just pass the whole strings. Commands like ~sync-cmd Windows 10 disks` are trickier. Because of how cmd.py works, we just have a flat string. Quotes at invocation time `sync-cmd vm "Windows 10" disks` don't make it through cmd.py. We can heuristically parse the names out though. Through introspection, we can get all valid command names. Search for a space prefixed " command" - since the command can't be first, it has to be prefixed. If found we can strip the remainder as the command string and search for the space-containing name. This means VmCmd has to tuck away the cmd_str for SyncCmd to recover. This is icky, but it will do the trick. Signed-off-by: Jason Andryuk --- pysynchronizer/cmd.py | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/pysynchronizer/cmd.py b/pysynchronizer/cmd.py index 0a7dbe2..e1be2d9 100644 --- a/pysynchronizer/cmd.py +++ b/pysynchronizer/cmd.py @@ -59,12 +59,10 @@ def do_upgrade(self, arg_str): self.do_xenmgr("upgrade " + arg_str) def do_vm(self, arg_str): - args = arg_str.split() - try: - if args: - vc = VmCmd(args[0]) - arg_str = " ".join(args[1:]) + if arg_str: + vc = VmCmd(arg_str) + arg_str = vc.cmd_str else: vc = VmCmd("") arg_str = "" @@ -162,20 +160,18 @@ def help_delete_vm(self): print('Usage: delete_vm [uuid|name]\n') print('Deletes VM matching either a uuid or a name\n') - def do_delete_vm(self, arg_str): - if not arg_str: + def do_delete_vm(self, vm_str): + if not vm_str: self.help_delete_vm() return - ref = arg_str.split()[0] - - vm_uuid = self.xenmgr.find_vm(ref) + vm_uuid = self.xenmgr.find_vm(vm_str) if vm_uuid: vm = VM(vm_uuid) vm.delete() else: - print('unable to find vm: %s\n' % ref) + print('unable to find vm: %s\n' % vm_str) def help_upgrade(self): print('Usage: upgrade "URL"\n') @@ -195,8 +191,20 @@ def __init__(self, arg_str): self.prompt = "vm> " - if arg_str: - self.select_vm(arg_str.split()[0]) + # Handle names with spaces. Default to full string as name + vm_str = arg_str + self.cmd_str = "" + # Find all possible commands: + cmds = [ x[3:] for x in self.__dir__() if x[:3] == "do_" ] + for cmd in cmds: + offset = arg_str.find(" " + cmd) + if offset != -1: + vm_str = arg_str[:offset] + self.cmd_str = arg_str[offset + 1:] + break + + if vm_str: + self.select_vm(vm_str) def select_vm(self, vm_ref): vm_uuid = XenMgr().find_vm(vm_ref) @@ -219,7 +227,7 @@ def do_select(self, arg_str): self.vm = None self.prompt = "vm> " - vm_ref = arg_str.split()[0] + vm_ref = arg_str self.select_vm(vm_ref) if self.vm is None: From 84f31bee6fe15a60e29951eafde2dce58e28cfac Mon Sep 17 00:00:00 2001 From: Jason Andryuk Date: Fri, 11 Feb 2022 13:37:43 -0500 Subject: [PATCH 12/18] sync-cmd: fix net create The `net create` expects to consume 3 args, but incorrectly checks that only one arg is passed. Additionally net_num needs to be an int, and only wired takes a mac in config, which needs to be prefixed "mac=". To enhance the command, reformat output from: Created: /wired/5/bridged /wired/5/shared /internal/5 /any/5 to: Created: /wired/5/bridged /wired/5/shared /internal/5 /any/5 Signed-off-by: Jason Andryuk --- pysynchronizer/cmd.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/pysynchronizer/cmd.py b/pysynchronizer/cmd.py index e1be2d9..a70ab42 100644 --- a/pysynchronizer/cmd.py +++ b/pysynchronizer/cmd.py @@ -466,16 +466,24 @@ def help_create(self): def do_create(self, arg_str): args = arg_str.split() - if len(args) != 1: + if len(args) != 3: self.help_create() return net_num, uuid, mac_addr = args[0], args[1], args[2] - config = "uuid=%s,%s,,,," % (uuid, mac_addr) + config_wired = "uuid=%s,mac=%s,,,," % (uuid, mac_addr) + config = "uuid=%s,,,,," % (uuid) + + nets = [] + nets.append(self.net.create_network('wired', int(net_num), config_wired)) + for net_type in ['internal', 'any']: + nets.append(self.net.create_network(net_type, int(net_num), config)) + # "wired" creates 2 - wired and shared. The others just 1. + nets = "".join(nets).split("\n") print("Created:") - for net_type in ['wired', 'internal', 'any']: - print("\t%s" % self.net.create_network(net_type, net_num, config)) + for net in nets: + print("\t%s" % net) def help_mac_addr(self): print('Usage: mac_addr network_object\n') From 665cec1bda8ff768a8a83896ec2a74aff36532ec Mon Sep 17 00:00:00 2001 From: Jason Andryuk Date: Mon, 14 Feb 2022 12:35:09 -0500 Subject: [PATCH 13/18] sync-cmd: usb: handle vm names/uuids The vusb-daemon only supports UUIDs for its policy checking. However nothing there or in sync-cmd enforces them. They could populate dbd, but could never be matched. Have sync-cmd lookup uuids and send those. Non-existant but validly formed UUIDs are passed through at this time. Signed-off-by: Jason Andryuk --- pysynchronizer/objects.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/pysynchronizer/objects.py b/pysynchronizer/objects.py index 600691c..2586a29 100644 --- a/pysynchronizer/objects.py +++ b/pysynchronizer/objects.py @@ -18,6 +18,7 @@ import dbus import os.path +import uuid from .utils import is_valid_uuid, dbus_path_to_uuid, uuid_to_dbus_path from .errors import Error, ConnectionError, ConfigError @@ -404,8 +405,24 @@ def set(self, key, value): self.__dict__[key] = int(value) return + # VM needs to be a UUID, so convert valid names + if key == 'vm': + # {Name, UUID} -> UUID string + vm = XenMgr().find_vm(value) + if vm: + self.__dict__[key] = vm + return + try: + u = uuid.UUID(value) + except: + raise ValueError("'%s' is neither a VM name nor a valid UUID" % value) from None + + # uuid doesn't exist - so maybe this should be an error? + self.__dict__[key] = value + return + # Handle all the keys that have string values - if key in ('cmd', 'desc', 'vid', 'pid', 'serial', 'vm'): + if key in ('cmd', 'desc', 'vid', 'pid', 'serial'): self.__dict__[key] = value return From 16b25a26652e4b1e70b48bf26ecf041fdd493db6 Mon Sep 17 00:00:00 2001 From: Jason Andryuk Date: Fri, 18 Feb 2022 10:22:02 -0500 Subject: [PATCH 14/18] sync-cmd: usb: allow spaces in desc sync-cmd usb set cannot currently handle spaces in the desc command. cmd.py is passing in a string, and it doesn't seem possible to get quotes down into the string. At least not in any sensible way. Parse the string in a custom fashion from back to front. That lets everything trailing the = to become the "value" and spaces can be handled. Signed-off-by: Jason Andryuk --- pysynchronizer/cmd.py | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/pysynchronizer/cmd.py b/pysynchronizer/cmd.py index a70ab42..04e5cce 100644 --- a/pysynchronizer/cmd.py +++ b/pysynchronizer/cmd.py @@ -413,9 +413,19 @@ def do_set(self, arg_str): arg_sep = '=' rule = UsbPolicyRule(None) # get an empty rule - args = shlex.split(arg_str) - for arg in args: - key, value = arg.split(arg_sep) + # Parse from back to front. This allows for whitespace like: + # idx=9000 desc=Desc with spaces cmd=running + while arg_str.rfind(arg_sep) != -1: + value_idx = arg_str.rfind(arg_sep) + value = arg_str[value_idx + 1:] + arg_str = arg_str[:value_idx] + key_idx = arg_str.rfind(" ") + if key_idx == -1: + key = arg_str + arg_str = "" + else: + key = arg_str[key_idx + 1:] + arg_str = arg_str[:key_idx] try: rule.set(key, value) @@ -423,6 +433,10 @@ def do_set(self, arg_str): print("Error: %s" % err) return + if len(arg_str) > 0: + print("Error parsing arguments: '%s'" % (arg_str)) + return + self.usb.policy_set_rule(rule) def help_remove(self): From 2648bb03b32b0b63d767ca8cb0793c8b9c5f19c8 Mon Sep 17 00:00:00 2001 From: Jason Andryuk Date: Mon, 5 Jun 2023 07:11:03 -0400 Subject: [PATCH 15/18] sync-cmd: require tls v1.2 as a minimum version Set the minimum version of TLS connections for sync-cmd to TLS 1.2. Signed-off-by: Jason Andryuk --- pysynchronizer/http_fetcher.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pysynchronizer/http_fetcher.py b/pysynchronizer/http_fetcher.py index b370224..d766219 100644 --- a/pysynchronizer/http_fetcher.py +++ b/pysynchronizer/http_fetcher.py @@ -48,6 +48,7 @@ def __cleanup_cert__(self): def setup_ssl_context(self): sslcont = ssl.create_default_context(ssl.Purpose.SERVER_AUTH) + sslcont.minimum_version = ssl.TLSVersion.TLSv1_2 if self.cacert != "": sslcont.load_verify_locations(cadata=self.cacert) From beb732f84cfb55dcf2887af0d2a6741f5bf95db8 Mon Sep 17 00:00:00 2001 From: eric gustafson Date: Wed, 14 Dec 2022 20:40:29 +0000 Subject: [PATCH 16/18] sync-cmd: make delete_vm command use xenmgr This moves the VM deletion logic to xenmgr where the unrestricted API may be used. Signed-off-by: Eric Gustafson --- pysynchronizer/cmd.py | 3 +-- pysynchronizer/objects.py | 8 ++++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/pysynchronizer/cmd.py b/pysynchronizer/cmd.py index 04e5cce..67db05e 100644 --- a/pysynchronizer/cmd.py +++ b/pysynchronizer/cmd.py @@ -168,8 +168,7 @@ def do_delete_vm(self, vm_str): vm_uuid = self.xenmgr.find_vm(vm_str) if vm_uuid: - vm = VM(vm_uuid) - vm.delete() + self.xenmgr.delete_vm(vm_uuid) else: print('unable to find vm: %s\n' % vm_str) diff --git a/pysynchronizer/objects.py b/pysynchronizer/objects.py index 2586a29..5ed716d 100644 --- a/pysynchronizer/objects.py +++ b/pysynchronizer/objects.py @@ -119,6 +119,14 @@ def create_vm(self, template, json): return str(unrestricted.unrestricted_create_vm_with_template_and_json(template, json)) + def delete_vm(self, uuid): + """Deletes the VM with designated by uuid""" + try: + unrestricted = OXTDBusApi.open_xenmgr_unrestricted() + except Exception as err: + raise ConnectionError('Failed to connect to XenMgr unrestricted service') from err + return str(unrestricted.unrestricted_delete_vm(uuid)) + def upgrade(self, url): """Takes a url, downloads it, and moves it for the upgrade manager to find""" storage = Storage() From 95e1fd9282b2c8482f22db7b6bad1b0f3871bc42 Mon Sep 17 00:00:00 2001 From: eric gustafson Date: Thu, 15 Dec 2022 16:25:04 +0000 Subject: [PATCH 17/18] sync-cmd: add shutdown and reboot commands Add ability to shutdown and reboot the system via sync-cmd. Signed-off-by: Eric Gustafson --- pysynchronizer/cmd.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/pysynchronizer/cmd.py b/pysynchronizer/cmd.py index 67db05e..a9bc6aa 100644 --- a/pysynchronizer/cmd.py +++ b/pysynchronizer/cmd.py @@ -184,6 +184,20 @@ def do_upgrade(self, arg_str): if not self.xenmgr.upgrade(arg_str.split()[0]): print('upgrade failed\n') + def help_shutdown(self): + print('Usage: shutdown\n') + print('Shutdown the host machine\n') + + def do_shutdown(self, arg_str): + self.xenmgr.host.shutdown(); + + def help_reboot(self): + print('Usage: reboot\n') + print('Reboot the host machine\n') + + def do_reboot(self, arg_str): + self.xenmgr.host.reboot() + class VmCmd(BaseCmd): def __init__(self, arg_str): super().__init__() From 139f50d3c792f60959b6010158a2940983db0d1f Mon Sep 17 00:00:00 2001 From: "Daniel P. Smith" Date: Mon, 5 Jun 2023 16:33:15 +0000 Subject: [PATCH 18/18] doc: add new doc folder with man page for sync-cmd Add a new doc folder to hold documentation and initially populate it with a man page for sync-cmd. The man page is rendered from Markdown using pandoc. Signed-off-by: Daniel P. Smith --- doc/sync-cmd.1 | 253 ++++++++++++++++++++++++++++++++++++++++++++++ doc/sync-cmd.1.md | 192 +++++++++++++++++++++++++++++++++++ 2 files changed, 445 insertions(+) create mode 100644 doc/sync-cmd.1 create mode 100644 doc/sync-cmd.1.md diff --git a/doc/sync-cmd.1 b/doc/sync-cmd.1 new file mode 100644 index 0000000..f457f98 --- /dev/null +++ b/doc/sync-cmd.1 @@ -0,0 +1,253 @@ +.\" Automatically generated by Pandoc 2.5 +.\" +.TH "SYNC\-CMD" "1" "" "Version 1.0" "Synchronizer Command Shell" +.hy +.SH NAME +.PP +\f[B]sync\-cmd\f[R] \[em] Command shell for administrating an OpenXT +system. +.SH SYNOPSIS +.PP +\f[B]sync\-cmd\f[R] [\f[B]command\f[R] [\f[B]\f[BI]arguments\f[B]\f[R]]] +.SH DESCRIPTION +.PP +Provides a command shell with an acceptable level of remote +administrative capabilities. +.SH BUILTIN COMMANDS +.SS xenmgr +.PP +Used to interact and manage xenmgr process. +.TP +.B release +Print the OpenXT release information for the current running software. +.TP +.B config +Provides two subcommands to interact with xenmgr config. +.PP +\ \ \ \ \ \ \ \f[B]\f[BI]subcommands:\f[B]\f[R] +.PD 0 +.P +.PD +.PD 0 +.P +.PD +\ \ \ \ \ \ \ get \f[I]property\f[R] +.PD 0 +.P +.PD +\ \ \ \ \ \ \ \ \ \ \ Retrieves \f[I]property\f[R] from xenmgr config. +.PD 0 +.P +.PD +.PD 0 +.P +.PD +\ \ \ \ \ \ \ set \f[I]property\f[R] \f[I]value\f[R] +.PD 0 +.P +.PD +\ \ \ \ \ \ \ \ \ \ \ Stores \f[I]value\f[R] in \f[I]property\f[R] of +xenmgr config. +.TP +.B vms +List all VMs on the system. +.TP +.B create_vm \f[I]template name\f[R] [\f[I]json file\f[R]] +Create a VM using the specified template and populate its config using +the optional JSON file. +.TP +.B delete_vm \f[I]identifier\f[R] +Delete a VM identified by identifier, where identifier may be the UUID +or the name of the VM. +.TP +.B upgrade \f[I]URL\f[R] +Initiate a platform upgrade using the OTA file located at \f[I]URL\f[R]. +.TP +.B reboot +Reboot the system. +.TP +.B shutdown +Shutdown the system. +.SS upgrade +.PP +Alias to \f[B]xenmgr upgrade\f[R] +.SS vm [\f[I]identifier\f[R]] +.PP +Used to interact and manage VM instances. +.TP +.B select [\f[I]identifier\f[R]] +In interactive mode, this selects the VM to act upon for subsequent +commands. +.TP +.B domstore +Provides two subcommands to configure a domains domstore. +.PP +\ \ \ \ \ \ \ \f[B]\f[BI]subcommands:\f[B]\f[R] +.PD 0 +.P +.PD +.PD 0 +.P +.PD +\ \ \ \ \ \ \ get \f[I]key\f[R] +.PD 0 +.P +.PD +\ \ \ \ \ \ \ \ \ \ \ Retrieves \f[I]key\f[R] from domstore. +.PD 0 +.P +.PD +.PD 0 +.P +.PD +\ \ \ \ \ \ \ set \f[I]key\f[R] \f[I]value\f[R] +.PD 0 +.P +.PD +\ \ \ \ \ \ \ \ \ \ \ Stores \f[I]value\f[R] for \f[I]key\f[R] in +domstore. +.TP +.B argo_firewall +Provides three subcommands to configure a domains argo firewall. +.PP +\ \ \ \ \ \ \ \f[B]\f[BI]subcommands:\f[B]\f[R] +.PD 0 +.P +.PD +.PD 0 +.P +.PD +\ \ \ \ \ \ \ list +.PD 0 +.P +.PD +\ \ \ \ \ \ \ \ \ \ \ Retrieves all the firewall rules. +.PD 0 +.P +.PD +.PD 0 +.P +.PD +\ \ \ \ \ \ \ add \f[I]rule\f[R] +.PD 0 +.P +.PD +\ \ \ \ \ \ \ \ \ \ \ Add \f[I]rule\f[R] to the firewall. +.PD 0 +.P +.PD +.PD 0 +.P +.PD +\ \ \ \ \ \ \ delete \f[I]rule\f[R] +.PD 0 +.P +.PD +\ \ \ \ \ \ \ \ \ \ \ If \f[I]rule\f[R] matches an existing rule, delete +it. +.TP +.B disks +List all disks associated with the VM. +.TP +.B disk +Provides subcommands to manage a disk associated with the VM. +.PP +\ \ \ \ \ \ \ \f[B]\f[BI]subcommands:\f[B]\f[R] +.PD 0 +.P +.PD +.PD 0 +.P +.PD +\ \ \ \ \ \ \ replace \f[I]URL\f[R] +.PD 0 +.P +.PD +\ \ \ \ \ \ \ \ \ \ \ Replace the backing disk image with one downloaded +from \f[I]URL\f[R]. +.SS usb +.PP +Used to manage the USB policy. +.TP +.B list +List all the rules in the USB policy. +.TP +.B show \f[I]num\f[R] | \f[I]all\f[R] +Display \f[I]num\f[R] rule in the USB policy, \f[I]all\f[R] will display +all rules. +.TP +.B set \f[I]rule\f[R] +Set a rule in the USB Policy as described by \f[I]rule\f[R]. +.TP +.B remove \f[I]num\f[R] +Remove rule number \f[I]num\f[R] from the USB policy. +.SS net +.PP +Used to manage the configuration for network instances. +.TP +.B list +List all network instances defined for the system. +.TP +.B create \f[I]id\f[R] \f[I]uuid\f[R] \f[I]mac\f[R] +Create a new network instance configured as follows, +.PP +\ \ \ \ \ \ \ \f[I]id\f[R]: network identifier +.PD 0 +.P +.PD +\ \ \ \ \ \ \ \f[I]uuid\f[R]: UUID of the backing domain for the network +.PD 0 +.P +.PD +\ \ \ \ \ \ \ \f[I]mac\f[R]: MAC address for the network bridge +.TP +.B mac_addr \f[I]obj\f[R] +Retrieve the MAC address for the network as identified by network object +\f[I]obj\f[R]. +.SH NOTES +.PP +The sync\-cmd functions by communicating with various system daemons +using DBus over Argo. +All DBus messages entering the control domain come through the +rpc\-proxy firewall. +The rpc\-proxy firewall provides a means to filter messages based on +source, destination, interface and member being invoked. +A portion of sync\-cmd functionality requires additional rpc\-proxy +firewall rules beyond those included in a vanilla build of OpenXT. +.SS Net Command Rules +.PP +To enable functionality of the \f[B]net\f[R] command, rules to allow the +following are required: +.IP +.nf +\f[C] +allow dom\-type syncvm destination com.citrix.xenclient.networkdaemon interface org.freedesktop.DBus.Introspectable member Introspect +allow dom\-type syncvm destination com.citrix.xenclient.networkdaemon interface com.citrix.xenclient.networkdaemon member list +allow dom\-type syncvm destination com.citrix.xenclient.networkdaemon interface com.citrix.xenclient.networkdaemon member create_network +\f[R] +.fi +.SS USB Command Rules +.PP +To enable functionality of the \f[B]usb\f[R] command, rules to allow the +following are required: +.IP +.nf +\f[C] +allow dom\-type syncvm destination com.citrix.xenclient.usbdaemon interface org.freedesktop.DBus.Introspectable member Introspect +allow dom\-type syncvm destination com.citrix.xenclient.usbdaemon interface com.citrix.xenclient.usbdaemon member policy_list +allow dom\-type syncvm destination com.citrix.xenclient.usbdaemon interface com.citrix.xenclient.usbdaemon member policy_get_rules +allow dom\-type syncvm destination com.citrix.xenclient.usbdaemon interface com.citrix.xenclient.usbdaemon member policy_set_rule +allow dom\-type syncvm destination com.citrix.xenclient.usbdaemon interface com.citrix.xenclient.usbdaemon member policy_set_rule_basic +allow dom\-type syncvm destination com.citrix.xenclient.usbdaemon interface com.citrix.xenclient.usbdaemon member policy_set_rule_advanced +allow dom\-type syncvm destination com.citrix.xenclient.usbdaemon interface com.citrix.xenclient.usbdaemon member policy_remove_rule +\f[R] +.fi +.SH BUGS +.PP +See GitHub Issues: +.SH AUTHOR +.PP +OpenXT Developers +.SH SEE ALSO +.PP +\f[B]sync\-cmd(1)\f[R] diff --git a/doc/sync-cmd.1.md b/doc/sync-cmd.1.md new file mode 100644 index 0000000..b814b6c --- /dev/null +++ b/doc/sync-cmd.1.md @@ -0,0 +1,192 @@ +% SYNC-CMD(1) Version 1.0 | Synchronizer Command Shell + +NAME +==== + +**sync-cmd** — Command shell for administrating an OpenXT system. + +SYNOPSIS +======== + +**sync-cmd** \[**command** [***arguments***]] + +DESCRIPTION +=========== + +Provides a command shell with an acceptable level of remote administrative +capabilities. + +BUILTIN COMMANDS +================= + +xenmgr +------ + +Used to interact and manage xenmgr process. + +release +: Print the OpenXT release information for the current running software. + +config +: Provides two subcommands to interact with xenmgr config. + +| ***subcommands:*** +| +| get _property_ +| Retrieves _property_ from xenmgr config. +| +| set _property_ _value_ +| Stores _value_ in _property_ of xenmgr config. + +vms +: List all VMs on the system. + +create_vm _template name_ [_json file_] +: Create a VM using the specified template and populate its config using the +optional JSON file. + +delete_vm _identifier_ +: Delete a VM identified by identifier, where identifier may be the UUID or +the name of the VM. + +upgrade _URL_ +: Initiate a platform upgrade using the OTA file located at _URL_. + +reboot +: Reboot the system. + +shutdown +: Shutdown the system. + +upgrade +------- + +Alias to **xenmgr upgrade** + +vm [_identifier_] +-- + +Used to interact and manage VM instances. + +select [_identifier_] +: In interactive mode, this selects the VM to act upon for subsequent commands. + +domstore +: Provides two subcommands to configure a domains domstore. + +| ***subcommands:*** +| +| get _key_ +| Retrieves _key_ from domstore. +| +| set _key_ _value_ +| Stores _value_ for _key_ in domstore. + +argo_firewall +: Provides three subcommands to configure a domains argo firewall. + +| ***subcommands:*** +| +| list +| Retrieves all the firewall rules. +| +| add _rule_ +| Add _rule_ to the firewall. +| +| delete _rule_ +| If _rule_ matches an existing rule, delete it. + +disks +: List all disks associated with the VM. + +disk +: Provides subcommands to manage a disk associated with the VM. + +| ***subcommands:*** +| +| replace _URL_ +| Replace the backing disk image with one downloaded from _URL_. + +usb +--- + +Used to manage the USB policy. + +list +: List all the rules in the USB policy. + +show _num_ | _all_ +: Display _num_ rule in the USB policy, _all_ will display all rules. + +set _rule_ +: Set a rule in the USB Policy as described by _rule_. + +remove _num_ +: Remove rule number _num_ from the USB policy. + +net +--- + +Used to manage the configuration for network instances. + +list +: List all network instances defined for the system. + +create _id_ _uuid_ _mac_ +: Create a new network instance configured as follows, + +| _id_: network identifier +| _uuid_: UUID of the backing domain for the network +| _mac_: MAC address for the network bridge + +mac_addr _obj_ +: Retrieve the MAC address for the network as identified by network object _obj_. + +NOTES +===== + +The sync-cmd functions by communicating with various system daemons using DBus over Argo. All DBus messages entering +the control domain come through the rpc-proxy firewall. The rpc-proxy firewall provides a means to filter messages +based on source, destination, interface and member being invoked. A portion of sync-cmd functionality requires additional +rpc-proxy firewall rules beyond those included in a vanilla build of OpenXT. + +Net Command Rules +----------------- + +To enable functionality of the **net** command, rules to allow the following are required: + +``` +allow dom-type syncvm destination com.citrix.xenclient.networkdaemon interface org.freedesktop.DBus.Introspectable member Introspect +allow dom-type syncvm destination com.citrix.xenclient.networkdaemon interface com.citrix.xenclient.networkdaemon member list +allow dom-type syncvm destination com.citrix.xenclient.networkdaemon interface com.citrix.xenclient.networkdaemon member create_network +``` + +USB Command Rules +----------------- + +To enable functionality of the **usb** command, rules to allow the following are required: + +``` +allow dom-type syncvm destination com.citrix.xenclient.usbdaemon interface org.freedesktop.DBus.Introspectable member Introspect +allow dom-type syncvm destination com.citrix.xenclient.usbdaemon interface com.citrix.xenclient.usbdaemon member policy_list +allow dom-type syncvm destination com.citrix.xenclient.usbdaemon interface com.citrix.xenclient.usbdaemon member policy_get_rules +allow dom-type syncvm destination com.citrix.xenclient.usbdaemon interface com.citrix.xenclient.usbdaemon member policy_set_rule +allow dom-type syncvm destination com.citrix.xenclient.usbdaemon interface com.citrix.xenclient.usbdaemon member policy_set_rule_basic +allow dom-type syncvm destination com.citrix.xenclient.usbdaemon interface com.citrix.xenclient.usbdaemon member policy_set_rule_advanced +allow dom-type syncvm destination com.citrix.xenclient.usbdaemon interface com.citrix.xenclient.usbdaemon member policy_remove_rule +``` + +BUGS +==== + +See GitHub Issues: + +AUTHOR +====== + +OpenXT Developers + +SEE ALSO +======== + +**sync-cmd(1)**