def print_props(cc, args):
        lstmsg = Commands._request_list(cc, API_LST_NODE, MsgLstNode())

        if lstmsg:
            for n in lstmsg.nodes:
                if n.name == args.node_name:
                    Commands._print_props(n.props)
                    break

        return None
Beispiel #2
0
    def print_props(cc, args):
        lstmsg = Commands._request_list(cc, API_LST_STOR_POOL, MsgLstStorPool())

        if lstmsg:
            for stp in lstmsg.stor_pools:
                if stp.stor_pool_name == args.storage_pool_name:
                    Commands._print_props(stp.props)
                    break

        return None
Beispiel #3
0
    def print_props(cc, args):
        lstmsg = Commands._request_list(cc, API_LST_RSC_DFN, MsgLstRscDfn())

        if lstmsg:
            for rsc_dfn in lstmsg.rsc_dfns:
                if rsc_dfn.rsc_name == args.resource_name:
                    Commands._print_props(rsc_dfn.rsc_dfn_props)
                    break

        return None
Beispiel #4
0
    def print_props(cc, args):
        lstmsg = Commands._request_list(cc, API_LST_RSC, MsgLstRsc())

        if lstmsg:
            for rsc in lstmsg.resources:
                if rsc.name == args.resource_name:
                    Commands._print_props(rsc.props)
                    break

        return None
Beispiel #5
0
    def list(cc, args):
        lstmsg = Commands._get_list_message(cc, API_LST_RSC, MsgLstRsc(), args)

        if lstmsg:
            rsc_dfns = Commands._get_list_message(cc, API_LST_RSC_DFN,
                                                  MsgLstRscDfn(),
                                                  args).rsc_dfns
            rsc_dfn_map = {x.rsc_name: x for x in rsc_dfns}

            stor_pools = Commands._get_list_message(cc, API_LST_STOR_POOL,
                                                    MsgLstStorPool(),
                                                    args).stor_pools
            stor_pool_map = {x.stor_pool_name: x for x in stor_pools}

            tbl = Table(utf8=not args.no_utf8,
                        colors=not args.no_color,
                        pastable=args.pastable)
            tbl.add_column("ResourceName")
            tbl.add_column("Node")
            tbl.add_column("Port")
            tbl.add_column("Device",
                           color=Output.color(Color.DARKGREEN, args.no_color))
            tbl.add_column("State",
                           color=Output.color(Color.DARKGREEN, args.no_color),
                           just_txt='>')

            for rsc in lstmsg.resources:
                rsc_dfn = rsc_dfn_map[rsc.name]
                diskless = FLAG_DISKLESS in rsc.rsc_flags
                if not diskless:
                    storage_pool_name = Commands._get_prop(
                        rsc.props, KEY_STOR_POOL_NAME)
                    storage_pool = stor_pool_map[storage_pool_name]
                    driver_key = StoragePoolCommands.get_driver_key(
                        storage_pool.driver)
                    block_device = Commands._get_prop(storage_pool.props,
                                                      driver_key)
                    # print(storage_pool)
                marked_delete = FLAG_DELETE in rsc.rsc_flags
                # rsc_state = ResourceCommands.find_rsc_state(lstmsg.resource_states, rsc.name, rsc.node_name)
                tbl.add_row([
                    rsc.name, rsc.node_name, rsc_dfn.rsc_dfn_port,
                    tbl.color_cell("DISKLESS", Color.GREEN)
                    if diskless else block_device,
                    tbl.color_cell("DELETING", Color.RED)
                    if marked_delete else "ok"
                ])
            tbl.show()

        return None
    def list(cc, args):
        lstmsg = Commands._get_list_message(cc, API_LST_NODE, MsgLstNode(),
                                            args)

        if lstmsg:
            tbl = Table(utf8=not args.no_utf8,
                        colors=not args.no_color,
                        pastable=args.pastable)
            tbl.add_column("Node")
            tbl.add_column("NodeType")
            tbl.add_column("IPs")
            tbl.add_column("State",
                           color=Output.color(Color.DARKGREEN, args.no_color))
            for n in lstmsg.nodes:
                ips = [if_.address for if_ in n.net_interfaces]
                tbl.add_row([
                    n.name, n.type, ",".join(ips),
                    tbl.color_cell("ok", Color.DARKGREEN)
                    if n.connected else tbl.color_cell("OFFLINE", Color.RED)
                ])
            tbl.show()

            # prntfrm = "{node:<20s} {type:<10s} {uuid:<40s}"
            # print(prntfrm.format(node="Node", type="NodeType", uuid="UUID"))

            # netiffrm = " +   {name:<20s} {address:>20s}"
            # for n in lstmsg.nodes:
            #     print(prntfrm.format(node=n.name, type=n.type, uuid=n.uuid))

            #     for interface in n.net_interfaces:
            #         print(netiffrm.format(
            #             name=interface.name,
            #             address=interface.address))

        return None
Beispiel #7
0
    def list(cc, args):
        lstmsg = Commands._get_list_message(cc, API_LST_RSC_DFN,
                                            MsgLstRscDfn(), args)

        if lstmsg:
            tbl = Table(utf8=not args.no_utf8,
                        colors=not args.no_color,
                        pastable=args.pastable)
            tbl.add_column("ResourceName")
            tbl.add_column("Port")
            tbl.add_column("State",
                           color=Output.color(Color.DARKGREEN, args.no_color))
            for rsc_dfn in lstmsg.rsc_dfns:
                tbl.add_row([
                    rsc_dfn.rsc_name, rsc_dfn.rsc_dfn_port,
                    tbl.color_cell("DELETING", Color.RED) if FLAG_DELETE
                    in rsc_dfn.rsc_dfn_flags else tbl.color_cell(
                        "ok", Color.DARKGREEN)
                ])
            tbl.show()

            # prntfrm = "{rsc:<20s} {port:<10s} {uuid:<40s}"
            # print(prntfrm.format(rsc="Resource-name", port="Port", uuid="UUID"))
            # for rsc_dfn in lstmsg.rsc_dfns:
            #     print(prntfrm.format(rsc=rsc_dfn.rsc_name,
            #           port=str(rsc_dfn.rsc_dfn_port), uuid=rsc_dfn.rsc_dfn_uuid))

        return None
    def delete(cc, args):
        del_msgs = []
        p = MsgDelNode()
        p.node_name = args.name

        del_msgs.append(p)

        return Commands._delete_and_output(cc, args, API_DEL_NODE, del_msgs)
Beispiel #9
0
    def setup_commands(parser):
        # new-storpol definition
        p_new_storpool_dfn = parser.add_parser(
            'create-storage-pool-definition',
            aliases=['crtstorpooldfn'],
            description='Defines a Linstor storpool definition for use with linstor.')
        p_new_storpool_dfn.add_argument(
            'name',
            type=namecheck(STORPOOL_NAME),
            help='Name of the new storpool definition')
        p_new_storpool_dfn.set_defaults(func=StoragePoolDefinitionCommands.create)

        # modify-storpool

        # remove-storpool definition
        # TODO description
        p_rm_storpool_dfn = parser.add_parser(
            'delete-storage-pool-definition',
            aliases=['delstorpooldfn'],
            description=' Removes a storage pool definition ')
        p_rm_storpool_dfn.add_argument('-q', '--quiet', action="store_true",
                                       help='Unless this option is used, linstor will issue a safety question '
                                       'that must be answered with yes, otherwise the operation is canceled.')
        p_rm_storpool_dfn.add_argument(
            'name',
            nargs="+",
            help='Name of the storage pool to delete').completer = StoragePoolDefinitionCommands.completer
        p_rm_storpool_dfn.set_defaults(func=StoragePoolDefinitionCommands.delete)

        # list storpool definitions
        storpooldfngroupby = ('Name')
        storpooldfn_group_completer = Commands.show_group_completer(storpooldfngroupby, "groupby")

        p_lstorpooldfs = parser.add_parser(
            'list-storage-pool-definitions',
            aliases=['list-storage-pool-definition', 'ls-storage-pool-dfn', 'display-storage-pool-definition',
                     'dspstorpooldfn'],
            description='Prints a list of all storage pool definitions known to '
            'linstor. By default, the list is printed as a human readable table.')
        p_lstorpooldfs.add_argument('-p', '--pastable', action="store_true", help='Generate pastable output')
        p_lstorpooldfs.add_argument('-g', '--groupby', nargs='+',
                                    choices=storpooldfngroupby).completer = storpooldfn_group_completer
        p_lstorpooldfs.add_argument(
            '-R', '--storpool', nargs='+', type=namecheck(STORPOOL_NAME),
            help='Filter by list of storage pool'
        ).completer = StoragePoolDefinitionCommands.completer
        p_lstorpooldfs.set_defaults(func=StoragePoolDefinitionCommands.list)

        # show properties
        p_sp = parser.add_parser(
            'get-storage-pool-definition-properties',
            aliases=['get-storage-pool-definition-props', 'dspstorpoolprp'],
            description="Prints all properties of the given storage pool definition.")
        p_sp.add_argument(
            'storage_pool_name',
            help="Storage pool definition for which to print the properties"
        ).completer = StoragePoolDefinitionCommands.completer
        p_sp.set_defaults(func=StoragePoolDefinitionCommands.print_props)
Beispiel #10
0
    def create(cc, args):
        p = MsgCrtRscDfn()
        p.rsc_dfn.rsc_name = args.name
        if args.port:
            p.rsc_dfn.rsc_dfn_port = args.port
        # if args.secret:
        #     p.secret = args.secret

        return Commands._create(cc, API_CRT_RSC_DFN, p, args)
Beispiel #11
0
    def delete(cc, args):
        del_msgs = []
        for rsc_name in args.name:
            p = MsgDelRscDfn()
            p.rsc_name = rsc_name

            del_msgs.append(p)

        return Commands._delete_and_output(cc, args, API_DEL_RSC_DFN, del_msgs)
Beispiel #12
0
    def delete(cc, args):
        del_msgs = []
        for storpool_name in args.name:
            p = MsgDelStorPoolDfn()
            p.stor_pool_name = storpool_name

            del_msgs.append(p)

        return Commands._delete_and_output(cc, args, API_DEL_STOR_POOL_DFN, del_msgs)
Beispiel #13
0
    def delete(cc, args):
        del_msgs = []
        for node_name in args.node_name:
            p = MsgDelStorPool()
            p.stor_pool_name = args.name
            p.node_name = node_name

            del_msgs.append(p)

        return Commands._delete_and_output(cc, args, API_DEL_STOR_POOL, del_msgs)
Beispiel #14
0
    def create(cc, args):
        p = MsgCrtVlmDfn()
        p.rsc_name = args.resource_name

        vlmdf = p.vlm_dfns.add()
        vlmdf.vlm_size = VolumeDefinitionCommands._get_volume_size(args.size)
        if args.minor is not None:
            vlmdf.vlm_minor = args.minor

        return Commands._create(cc, API_CRT_VLM_DFN, p, args)
Beispiel #15
0
    def delete(cc, args):
        del_msgs = []
        for node_name in args.node_name:
            p = MsgDelRsc()
            p.rsc_name = args.name
            p.node_name = node_name

            del_msgs.append(p)

        return Commands._delete_and_output(cc, args, API_DEL_RSC, del_msgs)
    def completer(cc, prefix, **kwargs):
        possible = set()
        lstmsg = Commands._get_list_message(cc, API_LST_NODE, MsgLstNode())

        if lstmsg:
            for node in lstmsg.nodes:
                possible.add(node.name)

            if prefix:
                return [node for node in possible if node.startswith(prefix)]

        return possible
Beispiel #17
0
    def completer(cc, prefix, **kwargs):
        possible = set()
        lstmsg = Commands._get_list_message(cc, API_LST_STOR_POOL, MsgLstStorPool())

        if lstmsg:
            for storpool in lstmsg.resources:
                possible.add(storpool.stor_pool_name)

            if prefix:
                return [res for res in possible if res.startswith(prefix)]

        return possible
Beispiel #18
0
    def completer(cc, prefix, **kwargs):
        possible = set()
        lstmsg = Commands._get_list_message(cc, API_LST_RSC, MsgLstRsc())

        if lstmsg:
            for rsc in lstmsg.resources:
                possible.add(rsc.name)

            if prefix:
                return [res for res in possible if res.startswith(prefix)]

        return possible
Beispiel #19
0
    def create(cc, args):
        p = MsgCrtRsc()
        p.rsc.name = args.resource_name
        p.rsc.node_name = args.node_name

        if not args.diskless and args.storage_pool:
            prop = LinStorMapEntry()
            prop.key = KEY_STOR_POOL_NAME
            prop.value = args.storage_pool
            p.rsc.props.extend([prop])

        if args.diskless:
            p.rsc.rsc_flags.append(FLAG_DISKLESS)

        return Commands._create(cc, API_CRT_RSC, p, args)
Beispiel #20
0
    def list_volumes(cc, args):
        lstmsg = Commands._get_list_message(cc, API_LST_RSC, MsgLstRsc(),
                                            args)  # type: MsgLstRsc

        if lstmsg:
            tbl = Table(utf8=not args.no_utf8,
                        colors=not args.no_color,
                        pastable=args.pastable)
            tbl.add_column("Node")
            tbl.add_column("Resource")
            tbl.add_column("VolumeNr")
            tbl.add_column("MinorNr")
            tbl.add_column("State",
                           color=Output.color(Color.DARKGREEN, args.no_color),
                           just_txt='>')

            for rsc in lstmsg.resources:
                rsc_state = ResourceCommands.get_resource_state(
                    lstmsg.resource_states, rsc.node_name, rsc.name)
                for vlm in rsc.vlms:
                    if rsc_state:
                        vlm_state = ResourceCommands.get_volume_state(
                            rsc_state.vlm_states, vlm.vlm_nr)
                    else:
                        vlm_state = None
                    state = tbl.color_cell("unknown", Color.YELLOW)
                    if vlm_state:
                        state = "ok"
                        problems = []
                        if not vlm_state.is_present:
                            problems.append("not present")
                        if vlm_state.disk_failed:
                            problems.append("disk failed")

                        if problems:
                            state = tbl.color_cell(", ".join(problems),
                                                   Color.RED)
                    tbl.add_row([
                        rsc.node_name, rsc.name,
                        str(vlm.vlm_nr),
                        str(vlm.vlm_minor_nr), state
                    ])

            tbl.show()

        return None
Beispiel #21
0
    def list(cc, args):
        lstmsg = Commands._get_list_message(cc, API_LST_STOR_POOL_DFN, MsgLstStorPoolDfn(), args)

        if lstmsg:
            tbl = Table(utf8=not args.no_utf8, colors=not args.no_color, pastable=args.pastable)
            tbl.add_column("StoragePool")
            for storpool_dfn in lstmsg.stor_pool_dfns:
                tbl.add_row([
                    storpool_dfn.stor_pool_name
                ])
            tbl.show()

            # prntfrm = "{storpool:<20s} {uuid:<40s}"
            # print(prntfrm.format(storpool="StorpoolDfn-name", uuid="UUID"))
            # for storpool_dfn in lstmsg.stor_pool_dfns:
            #     print(prntfrm.format(storpool=storpool_dfn.stor_pool_name, uuid=storpool_dfn.uuid))

        return None
Beispiel #22
0
    def create(cc, args):
        p = MsgCrtStorPool()
        p.stor_pool.stor_pool_name = args.name
        p.stor_pool.node_name = args.node_name

        # construct correct driver name
        if args.driver == 'lvmthin':
            driver = 'LvmThin'
        else:
            driver = args.driver.title()

        p.stor_pool.driver = '{driver}Driver'.format(driver=driver)

        # set driver device pool property
        prop = p.stor_pool.props.add()
        prop.key = StoragePoolCommands.device_key_map[driver]
        prop.value = args.driver_device

        return Commands._create(cc, API_CRT_STOR_POOL, p, args)
Beispiel #23
0
    def list(cc, args):
        lstmsg = Commands._get_list_message(cc, API_LST_RSC_DFN,
                                            MsgLstRscDfn(), args)

        if lstmsg:
            tbl = Table(utf8=not args.no_utf8,
                        colors=not args.no_color,
                        pastable=args.pastable)
            tbl.add_column("ResourceName")
            tbl.add_column("VolumeNr")
            tbl.add_column("VolumeMinor")
            tbl.add_column("Size")
            tbl.add_column("State",
                           color=Output.color(Color.DARKGREEN, args.no_color))
            for rsc_dfn in lstmsg.rsc_dfns:
                for vlmdfn in rsc_dfn.vlm_dfns:
                    tbl.add_row([
                        rsc_dfn.rsc_name, vlmdfn.vlm_nr, vlmdfn.vlm_minor,
                        approximate_size_string(vlmdfn.vlm_size),
                        tbl.color_cell("DELETING", Color.RED) if FLAG_DELETE
                        in rsc_dfn.rsc_dfn_flags else tbl.color_cell(
                            "ok", Color.DARKGREEN)
                    ])
            tbl.show()

            # prntfrm = "{res:<15s} {uuid:<40s} {vlmnr:<5s} {vlmminor:<10s} {vlmsize:<10s}"
            # print(prntfrm.format(res="Resource", uuid="UUID", vlmnr="VlmNr", vlmminor="VlmMinor", vlmsize="Size"))
            # prntfrm = "{res:<15s} {uuid:<40s} {vlmnr:<5d} {vlmminor:<10d} {vlmsize:<20s}"
            # for rscdfn in lstmsg.rsc_dfns:
            #     for vlmdfn in rscdfn.vlm_dfns:
            #         print(prntfrm.format(
            #             res=rscdfn.rsc_name,
            #             uuid=vlmdfn.vlm_dfn_uuid,
            #             vlmnr=vlmdfn.vlm_nr,
            #             vlmminor=vlmdfn.vlm_minor,
            #             vlmsize=approximate_size_string(vlmdfn.vlm_size)))

        return None
    def create(cc, args):
        p = MsgCrtNode()

        def gen_nif(k, v):
            prop = LinStorMapEntry()
            prop.key = "%s/%s/%s" % (NAMESPC_NETIF, args.interface_name, k)
            prop.value = v
            p.node.props.extend([prop])

        # interface
        gen_nif(KEY_NETIF_TYPE, args.interface_type)
        gen_nif(KEY_NETCOM_TYPE, args.communication_type)

        p.node.name = args.name
        p.node.type = args.node_type

        netif = p.node.net_interfaces.add()
        netif.name = args.interface_name
        netif.address = args.ip

        port = args.port
        if not port:
            if args.communication_type == VAL_NETCOM_TYPE_PLAIN:
                port = DFLT_CTRL_PORT_PLAIN if p.node.type == VAL_NODE_TYPE_CTRL else DFLT_STLT_PORT_PLAIN
            elif args.communication_type == VAL_NETCOM_TYPE_SSL:
                port = DFLT_CTRL_PORT_SSL
            else:
                Output.err(
                    "Communication type %s has no default port" %
                    (args.communication_type), args.no_color)
        gen_nif(KEY_PORT_NR, str(port))

        satcon = p.satellite_connections.add()
        satcon.net_interface_name = args.interface_name
        satcon.port = port
        satcon.encryption_type = args.communication_type

        return Commands._create(cc, API_CRT_NODE, p, args)
Beispiel #25
0
    def list(cc, args):
        lstmsg = Commands._get_list_message(cc, API_LST_STOR_POOL, MsgLstStorPool(), args)

        if lstmsg:
            tbl = Table(utf8=not args.no_utf8, colors=not args.no_color, pastable=args.pastable)
            tbl.add_column("StoragePool")
            tbl.add_column("Node")
            tbl.add_column("Driver")
            tbl.add_column("DriverDevice")
            tbl.add_column("SupportsSnapshots")
            for storpool in lstmsg.stor_pools:
                driver_device_prop = [x for x in storpool.props
                                      if x.key == StoragePoolCommands.device_key_map[storpool.driver[:-len('Driver')]]]
                driver_device = driver_device_prop[0].value if driver_device_prop else ''

                supports_snapshots_prop = [x for x in storpool.static_traits if x.key == KEY_STOR_POOL_SUPPORTS_SNAPSHOTS]
                supports_snapshots = supports_snapshots_prop[0].value if supports_snapshots_prop else ''

                tbl.add_row([
                    storpool.stor_pool_name,
                    storpool.node_name,
                    storpool.driver,
                    driver_device,
                    supports_snapshots
                ])
            tbl.show()

            # prntfrm = "{storpool:<20s} {uuid:<40s} {node:<30s} {driver:<20s}"
            # print(prntfrm.format(storpool="Storpool-name", uuid="UUID", node="Node", driver="Driver"))
            # for storpool in lstmsg.stor_pools:
            #     print(prntfrm.format(
            #         storpool=storpool.stor_pool_name,
            #         uuid=storpool.stor_pool_uuid,
            #         node=storpool.node_name,
            #         driver=storpool.driver))

        return None
Beispiel #26
0
    def setup_commands(parser):
        # new-resource
        p_new_res = parser.add_parser(
            'create-resource',
            aliases=['crtrsc'],
            description='Defines a DRBD resource for use with linstor. '
            'Unless a specific IP port-number is supplied, the port-number is '
            'automatically selected by the linstor controller on the current node. '
        )
        p_new_res.add_argument(
            '-s',
            '--storage-pool',
            type=namecheck(STORPOOL_NAME),
            help="Storage pool name to use."
        ).completer = StoragePoolDefinitionCommands.completer
        p_new_res.add_argument('-d',
                               '--diskless',
                               action="store_true",
                               help='Should the resource be diskless')
        p_new_res.add_argument(
            'resource_name',
            type=namecheck(RES_NAME),
            help='Name of the resource definition'
        ).completer = ResourceDefinitionCommands.completer
        p_new_res.add_argument(
            'node_name',
            type=namecheck(NODE_NAME),
            help='Name of the new resource').completer = NodeCommands.completer
        p_new_res.set_defaults(func=ResourceCommands.create)

        # modify-resource
        p_mod_res_command = 'modify-resource'
        p_mod_res = parser.add_parser(p_mod_res_command,
                                      aliases=['mfyrsc', 'mr'],
                                      description='Modifies a DRBD resource.')
        p_mod_res.add_argument('-m',
                               '--managed',
                               choices=(BOOL_TRUE, BOOL_FALSE))
        p_mod_res.add_argument(
            'name', type=namecheck(RES_NAME),
            help='Name of the resource').completer = ResourceCommands.completer
        p_mod_res.set_defaults(func=Commands.cmd_enoimp)
        p_mod_res.set_defaults(command=p_mod_res_command)

        # remove-resource
        p_rm_res = parser.add_parser(
            'delete-resource',
            aliases=['delrsc'],
            description=
            ' Removes a resource and its associated resource definition '
            'from the linstor cluster. The resource is undeployed from all nodes '
            "and the resource entry is marked for removal from linstor's data "
            'tables. After all nodes have undeployed the resource, the resource '
            "entry is removed from linstor's data tables.")
        p_rm_res.add_argument(
            '-q',
            '--quiet',
            action="store_true",
            help=
            'Unless this option is used, linstor will issue a safety question '
            'that must be answered with yes, otherwise the operation is canceled.'
        )
        p_rm_res.add_argument('name', help='Name of the resource to delete'
                              ).completer = ResourceCommands.completer
        p_rm_res.add_argument(
            'node_name', nargs="+",
            help='Name of the node').completer = NodeCommands.completer
        p_rm_res.set_defaults(func=ResourceCommands.delete)

        resverbose = ('Port', )
        resgroupby = ('Name', 'Port', 'State')
        res_verbose_completer = Commands.show_group_completer(
            resverbose, "show")
        res_group_completer = Commands.show_group_completer(
            resgroupby, "groupby")

        p_lreses = parser.add_parser(
            'list-resources',
            aliases=['list-resource', 'ls-rsc', 'display-resources', 'dsprsc'],
            description='Prints a list of all resource definitions known to '
            'linstor. By default, the list is printed as a human readable table.'
        )
        p_lreses.add_argument('-p',
                              '--pastable',
                              action="store_true",
                              help='Generate pastable output')
        p_lreses.add_argument(
            '-s', '--show', nargs='+',
            choices=resverbose).completer = res_verbose_completer
        p_lreses.add_argument(
            '-g', '--groupby', nargs='+',
            choices=resgroupby).completer = res_group_completer
        p_lreses.add_argument('-R',
                              '--resources',
                              nargs='+',
                              type=namecheck(RES_NAME),
                              help='Filter by list of resources'
                              ).completer = ResourceCommands.completer
        p_lreses.set_defaults(func=ResourceCommands.list)

        # list volumes
        p_lvlms = parser.add_parser(
            'list-volumes',
            aliases=['list-volume', 'ls-vlm', 'display-volumes', 'dspvlm'],
            description='Prints a list of all volumes.')
        p_lvlms.add_argument('-p',
                             '--pastable',
                             action="store_true",
                             help='Generate pastable output')
        p_lvlms.add_argument('resource', nargs='?')
        p_lvlms.set_defaults(func=ResourceCommands.list_volumes)

        # show properties
        p_sp = parser.add_parser(
            'get-resource-properties',
            aliases=['get-resource-props', 'dsprscprp'],
            description="Prints all properties of the given resource.")
        p_sp.add_argument('resource_name',
                          help="Resource for which to print the properties"
                          ).completer = ResourceCommands.completer
        p_sp.set_defaults(func=ResourceCommands.print_props)
Beispiel #27
0
    def delete(cc, args):
        p = MsgDelVlmDfn()
        p.rsc_name = args.resource_name
        p.vlm_nr = args.volume_nr

        return Commands._delete_and_output(cc, args, API_DEL_VLM_DFN, [p])
Beispiel #28
0
    def setup_commands(parser):
        p_new_res_dfn = parser.add_parser(
            'create-resource-definition',
            aliases=['crtrscdfn'],
            description=
            'Defines a Linstor resource definition for use with linstor.')
        p_new_res_dfn.add_argument('-p', '--port', type=rangecheck(1, 65535))
        # p_new_res_dfn.add_argument('-s', '--secret', type=str)
        p_new_res_dfn.add_argument('name',
                                   type=namecheck(RES_NAME),
                                   help='Name of the new resource definition')
        p_new_res_dfn.set_defaults(func=ResourceDefinitionCommands.create)

        # remove-resource definition
        # TODO description
        p_rm_res_dfn = parser.add_parser(
            'delete-resource-definition',
            aliases=['delrscdfn'],
            description=" Removes a resource definition "
            "from the linstor cluster. The resource is undeployed from all nodes "
            "and the resource entry is marked for removal from linstor's data "
            "tables. After all nodes have undeployed the resource, the resource "
            "entry is removed from linstor's data tables.")
        p_rm_res_dfn.add_argument(
            '-q',
            '--quiet',
            action="store_true",
            help=
            'Unless this option is used, linstor will issue a safety question '
            'that must be answered with yes, otherwise the operation is canceled.'
        )
        p_rm_res_dfn.add_argument(
            'name', nargs="+", help='Name of the resource to delete'
        ).completer = ResourceDefinitionCommands.completer
        p_rm_res_dfn.set_defaults(func=ResourceDefinitionCommands.delete)

        resverbose = ('Port', )
        resgroupby = ('Name', 'Port', 'State')
        res_verbose_completer = Commands.show_group_completer(
            resverbose, "show")
        res_group_completer = Commands.show_group_completer(
            resgroupby, "groupby")

        p_lrscdfs = parser.add_parser(
            'list-resource-definitions',
            aliases=[
                'list-resource-definition', 'dsprscdfn',
                'display-resource-definitions', 'resource-definitions',
                'dsprscdfn'
            ],
            description='Prints a list of all resource definitions known to '
            'linstor. By default, the list is printed as a human readable table.'
        )
        p_lrscdfs.add_argument('-p',
                               '--pastable',
                               action="store_true",
                               help='Generate pastable output')
        p_lrscdfs.add_argument(
            '-s', '--show', nargs='+',
            choices=resverbose).completer = res_verbose_completer
        p_lrscdfs.add_argument(
            '-g', '--groupby', nargs='+',
            choices=resgroupby).completer = res_group_completer
        p_lrscdfs.add_argument(
            '-R',
            '--resources',
            nargs='+',
            type=namecheck(RES_NAME),
            help='Filter by list of resources'
        ).completer = ResourceDefinitionCommands.completer
        p_lrscdfs.set_defaults(func=ResourceDefinitionCommands.list)

        # show properties
        p_sp = parser.add_parser(
            'get-resource-definition-properties',
            aliases=['get-resource-definition-props', 'dsprscdfnprp'],
            description=
            "Prints all properties of the given resource definitions.")
        p_sp.add_argument(
            'resource_name',
            help="Resource definition for which to print the properties"
        ).completer = ResourceDefinitionCommands.completer
        p_sp.set_defaults(func=ResourceDefinitionCommands.print_props)
Beispiel #29
0
    def setup_commands(parser):
        p_new_vol_command = 'create-volume-definition'
        p_new_vol = parser.add_parser(
            p_new_vol_command,
            aliases=['crtvlmdfn'],
            description='Defines a volume with a capacity of size for use with '
            'linstore. If the resource resname exists already, a new volume is '
            'added to that resource, otherwise the resource is created automatically '
            'with default settings. Unless minornr is specified, a minor number for '
            "the volume's DRBD block device is assigned automatically by the "
            'linstor server.')
        p_new_vol.add_argument('-m', '--minor', type=int)
        p_new_vol.add_argument('-d', '--deploy', type=int)
        p_new_vol.add_argument('-s',
                               '--site',
                               default='',
                               help="only consider nodes from this site")
        p_new_vol.add_argument(
            'resource_name',
            type=namecheck(RES_NAME),
            help='Name of an existing resource'
        ).completer = ResourceDefinitionCommands.completer
        p_new_vol.add_argument(
            'size',
            help='Size of the volume in resource. '
            'The default unit for size is GiB (size * (2 ^ 30) bytes). '
            'Another unit can be specified by using an according postfix. '
            "Linstor's internal granularity for the capacity of volumes is one "
            'Kibibyte (2 ^ 10 bytes). All other unit specifications are implicitly '
            'converted to Kibibyte, so that the actual size value used by linstor '
            'is the smallest natural number of Kibibytes that is large enough to '
            'accommodate a volume of the requested size in the specified size unit.'
        ).completer = VolumeDefinitionCommands.size_completer
        p_new_vol.set_defaults(func=VolumeDefinitionCommands.create)
        p_new_vol.set_defaults(command=p_new_vol_command)

        # remove-volume definition
        p_rm_vol = parser.add_parser(
            'delete-volume-definition',
            aliases=['delvlmdfn'],
            description=
            'Removes a volume definition from the linstor cluster, and removes '
            'the volume definition from the resource definition. The volume is '
            'undeployed from all nodes and the volume entry is marked for removal '
            "from the resource definition in linstor's data tables. After all "
            'nodes have undeployed the volume, the volume entry is removed from '
            'the resource definition.')
        p_rm_vol.add_argument(
            '-q',
            '--quiet',
            action="store_true",
            help=
            'Unless this option is used, linstor will issue a safety question '
            'that must be answered with yes, otherwise the operation is canceled.'
        )
        p_rm_vol.add_argument(
            'resource_name', help='Resource name of the volume definition'
        ).completer = ResourceDefinitionCommands.completer
        p_rm_vol.add_argument('volume_nr',
                              type=int,
                              help="Volume number to delete.")
        p_rm_vol.set_defaults(func=VolumeDefinitionCommands.delete)

        # list volume definitions
        resgroupby = ()
        volgroupby = resgroupby + ('Vol_ID', 'Size', 'Minor')
        vol_group_completer = Commands.show_group_completer(
            volgroupby, 'groupby')

        p_lvols = parser.add_parser(
            'list-volume-definitions',
            aliases=[
                'list-volume-definition', 'dspvlmdfn',
                'display-volume-definitions', 'volume-definitions', 'dspvlmdfn'
            ],
            description=
            ' Prints a list of all volume definitions known to linstor. '
            'By default, the list is printed as a human readable table.')
        p_lvols.add_argument('-p',
                             '--pastable',
                             action="store_true",
                             help='Generate pastable output')
        p_lvols.add_argument(
            '-g', '--groupby', nargs='+',
            choices=volgroupby).completer = vol_group_completer
        p_lvols.add_argument('-R',
                             '--resources',
                             nargs='+',
                             type=namecheck(RES_NAME),
                             help='Filter by list of resources'
                             ).completer = ResourceDefinitionCommands.completer
        p_lvols.set_defaults(func=VolumeDefinitionCommands.list)
Beispiel #30
0
    def setup_parser(self):
        parser = argparse.ArgumentParser(prog="linstor")
        parser.add_argument('--version',
                            '-v',
                            action='version',
                            version='%(prog)s ' + VERSION + '; ' + GITHASH)
        parser.add_argument(
            '--no-color',
            action="store_true",
            help=
            'Do not use colors in output. Useful for old terminals/scripting.')
        parser.add_argument(
            '--no-utf8',
            action="store_true",
            help='Do not use utf-8 characters in output (i.e., tables).')
        parser.add_argument(
            '--warn-as-error',
            action="store_true",
            help='Treat WARN return code as error (i.e., return code > 0).')
        parser.add_argument(
            '--controllers',
            default='localhost:%d' % DFLT_CTRL_PORT_PLAIN,
            help=
            'Comma separated list of controllers (e.g.: "host1:port,host2:port"). '
            'If the environment variable %s is set, '
            'the ones set via this argument get appended.' %
            KEY_LS_CONTROLLERS)
        parser.add_argument('-m', '--machine-readable', action="store_true")
        parser.add_argument('-t',
                            '--timeout',
                            default=20,
                            type=int,
                            help="Connection timeout value.")
        parser.add_argument(
            '--disable-config',
            action="store_true",
            help="Disable config loading and only use commandline arguments.")

        subp = parser.add_subparsers(title='subcommands',
                                     description='valid subcommands',
                                     help='Use the list command to print a '
                                     'nicer looking overview of all valid '
                                     'commands')

        # interactive mode
        parser_ia = subp.add_parser('interactive',
                                    description='Start interactive mode')
        parser_ia.set_defaults(func=self.cmd_interactive)

        # help
        p_help = subp.add_parser('help',
                                 description='Print help for a command')
        p_help.add_argument('command')
        p_help.set_defaults(func=self.cmd_help)

        # list
        p_list = subp.add_parser('list',
                                 aliases=['commands', 'list-commands'],
                                 description='List available commands')
        p_list.set_defaults(func=self.cmd_list)

        # exit
        p_exit = subp.add_parser('exit',
                                 aliases=['quit'],
                                 description='Only useful in interactive mode')
        p_exit.set_defaults(func=self.cmd_exit)

        # poke
        p_poke = subp.add_parser('poke')
        p_poke.add_argument('-q', '--quiet', action="store_true")
        p_poke.set_defaults(func=self.cmd_enoimp)

        # type checkers (generate them only once)
        check_node_name = namecheck(NODE_NAME)
        check_res_name = namecheck(RES_NAME)
        check_snaps_name = namecheck(SNAPS_NAME)

        # Quorum control, completion of the action parameter
        quorum_completer_possible = ('ignore', 'unignore')

        def quorum_action_completer(prefix, **kwargs):
            possible = list(quorum_completer_possible)
            if prefix is not None and prefix != "":
                possible = [
                    item for item in possible if item.startswith(prefix)
                ]
            return possible

        p_quorum = subp.add_parser(
            "quorum-control",
            aliases=["qc"],
            description="Sets quorum parameters on linstor cluster nodes")
        p_quorum.add_argument(
            '-o',
            '--override',
            action="store_true",
            help="Override change protection in a partition without quorum")
        p_quorum.add_argument(
            "action",
            choices=quorum_completer_possible,
            help="The action to perform on the affected nodes"
        ).completer = quorum_action_completer
        p_quorum.add_argument("name",
                              nargs="+",
                              type=check_node_name,
                              help="Name of the affected node or nodes"
                              ).completer = NodeCommands.completer
        p_quorum.set_defaults(func=self.cmd_enoimp)

        # add all node commands
        NodeCommands.setup_commands(subp)

        # new-resource definition
        ResourceDefinitionCommands.setup_commands(subp)

        # add all resource commands
        ResourceCommands.setup_commands(subp)

        # add all storage pool definition commands
        StoragePoolDefinitionCommands.setup_commands(subp)

        # add all storage pools commands
        StoragePoolCommands.setup_commands(subp)

        # add all volume definition commands
        VolumeDefinitionCommands.setup_commands(subp)

        def vol_completer(prefix, parsed_args, **kwargs):
            server_rc, res_list = self.__list_resources(True)
            possible = set()
            for r in res_list:
                name, _, vol_list = r
                if name == parsed_args.name:
                    vol_list.sort(key=lambda vol_entry: vol_entry[0])
                    for v in vol_list:
                        vol_id, _ = v
                        possible.add(str(vol_id))

            return possible

        # resize-volume
        p_resize_vol_command = 'resize-volume'
        p_resize_vol = subp.add_parser(
            p_resize_vol_command,
            aliases=['resize'],
            description='Resizes a volume to the specified size, which must be '
            'greater than the current size of the volume.')
        p_resize_vol.add_argument(
            'name', type=check_res_name,
            help='Name of the resource').completer = ResourceCommands.completer
        p_resize_vol.add_argument('id', help='Volume ID',
                                  type=int).completer = vol_completer
        p_resize_vol.add_argument(
            'size',
            help='New size of the volume. '
            'The default unit for size is GiB (size * (2 ^ 30) bytes). '
            'Another unit can be specified by using an according postfix. '
            "linstor's internal granularity for the capacity of volumes is one "
            'Kibibyte (2 ^ 10 bytes). All other unit specifications are implicitly '
            'converted to Kibibyte, so that the actual size value used by linstor '
            'is the smallest natural number of Kibibytes that is large enough to '
            'accommodate a volume of the requested size in the specified size unit.'
        ).completer = VolumeDefinitionCommands.size_completer
        p_resize_vol.set_defaults(func=self.cmd_enoimp)
        p_resize_vol.set_defaults(command=p_resize_vol_command)

        # connect
        p_conn = subp.add_parser('connect-resource',
                                 description='Connect resource on node',
                                 aliases=['connect'])
        p_conn.add_argument(
            'resource',
            type=check_res_name).completer = ResourceCommands.completer
        p_conn.add_argument(
            'node', type=check_node_name).completer = NodeCommands.completer
        p_conn.set_defaults(func=self.cmd_enoimp)

        # reconnect
        p_reconn = subp.add_parser('reconnect-resource',
                                   description='Reconnect resource on node',
                                   aliases=['reconnect'])
        p_reconn.add_argument(
            'resource',
            type=check_res_name).completer = ResourceCommands.completer
        p_reconn.add_argument(
            'node', type=check_node_name).completer = NodeCommands.completer
        p_reconn.set_defaults(func=self.cmd_enoimp)

        # disconnect
        p_disconn = subp.add_parser('disconnect-resource',
                                    description='Disconnect resource on node',
                                    aliases=['disconnect'])
        p_disconn.add_argument(
            'resource',
            type=check_res_name).completer = ResourceCommands.completer
        p_disconn.add_argument(
            'node', type=check_node_name).completer = NodeCommands.completer
        p_disconn.set_defaults(func=self.cmd_enoimp)

        # flags
        p_flags = subp.add_parser('set-flags',
                                  description='Set flags of resource on node',
                                  aliases=['flags'])
        p_flags.add_argument(
            'resource', type=check_res_name,
            help='Name of the resource').completer = ResourceCommands.completer
        p_flags.add_argument(
            'node', type=check_node_name,
            help='Name of the node').completer = NodeCommands.completer
        p_flags.add_argument('--reconnect', choices=(0, 1), type=int)
        p_flags.add_argument('--updcon', choices=(0, 1), type=int)
        p_flags.add_argument('--overwrite', choices=(0, 1), type=int)
        p_flags.add_argument('--discard', choices=(0, 1), type=int)
        p_flags.set_defaults(func=self.cmd_enoimp)

        # free space
        def redundancy_type(r):
            r = int(r)
            if r < 1:
                raise argparse.ArgumentTypeError('Minimum redundancy is 1')
            return r

        p_fspace = subp.add_parser('list-free-space',
                                   description='Queries the maximum size of a'
                                   ' volume that could be deployed with the'
                                   ' specified level of redundancy',
                                   aliases=['free-space'])
        p_fspace.add_argument('-s',
                              '--site',
                              default='',
                              help="only consider nodes from this site")
        p_fspace.add_argument('redundancy',
                              type=redundancy_type,
                              help='Redundancy level (>=1)')
        p_fspace.set_defaults(func=self.cmd_enoimp)

        # deploy
        p_deploy = subp.add_parser(
            'deploy-resource',
            aliases=['deploy'],
            description='Deploys a resource on n automatically selected nodes '
            "of the linstor cluster. Using the information in linstor's data "
            'tables, the linstor server tries to find n nodes that have enough '
            'free storage capacity to deploy the resource resname.')
        p_deploy.add_argument(
            'resource',
            type=check_res_name).completer = ResourceCommands.completer
        p_deploy.add_argument('-i',
                              '--increase',
                              action="store_true",
                              help='Increase the redundancy count relative to'
                              ' the currently set value by a number of'
                              ' <redundancy_count>')
        p_deploy.add_argument('-d',
                              '--decrease',
                              action="store_true",
                              help='Decrease the redundancy count relative to'
                              ' the currently set value by a number of'
                              ' <redundancy_count>')
        p_deploy.add_argument('redundancy_count',
                              type=redundancy_type,
                              help='The redundancy count specifies the number'
                              ' of nodes to which the resource should be'
                              ' deployed. It must be at least 1 and at most'
                              ' the number of nodes in the cluster')
        p_deploy.add_argument('--with-clients', action="store_true")
        p_deploy.add_argument('-s',
                              '--site',
                              default='',
                              help="only consider nodes from this site")
        p_deploy.set_defaults(func=self.cmd_enoimp)

        # undeploy
        p_undeploy = subp.add_parser(
            'undeploy-resource',
            aliases=['undeploy'],
            description='Undeploys a resource from all nodes. The resource '
            "definition is still kept in linstor's data tables.")
        p_undeploy.add_argument('-q', '--quiet', action="store_true")
        p_undeploy.add_argument('-f', '--force', action="store_true")
        p_undeploy.add_argument(
            'resource',
            type=check_res_name).completer = ResourceCommands.completer
        p_undeploy.set_defaults(func=self.cmd_enoimp)

        # update-pool
        p_upool = subp.add_parser(
            'update-pool',
            description='Checks the storage pool total size and free space on '
            'the local node and updates the associated values in the data '
            'tables on the control volume.')
        p_upool.set_defaults(func=self.cmd_enoimp)

        # new-snapshot
        p_nsnap = subp.add_parser(
            'add-snapshot',
            aliases=['ns', 'create-snapshot', 'cs', 'new-snapshot', 'as'],
            description='Create a LVM snapshot')
        p_nsnap.add_argument('snapshot',
                             type=check_snaps_name,
                             help='Name of the snapshot')
        p_nsnap.add_argument(
            'resource', type=check_res_name,
            help='Name of the resource').completer = ResourceCommands.completer
        p_nsnap.add_argument('nodes',
                             type=check_node_name,
                             help='List of nodes',
                             nargs='+').completer = NodeCommands.completer
        p_nsnap.set_defaults(func=self.cmd_enoimp)

        # Snapshot commands:
        # These commands do not follow the usual option order:
        # For example remove-snapshot should have the snapshot name as first argument and the resource as
        # second argument. BUT: There are (potentially) more snapshots than resources, so specifying the
        # resource first and then completing only the snapshots for that resource makes more sense.

        # remove-snapshot
        def snaps_completer(prefix, parsed_args, **kwargs):
            server_rc, res_list = self._list_snapshots()
            possible = set()
            for r in res_list:
                res_name, snaps_list = r
                if res_name == parsed_args.resource:
                    for s in snaps_list:
                        snaps_name, _ = s
                        possible.add(snaps_name)

            return possible

        p_rmsnap = subp.add_parser(
            'remove-snapshot',
            aliases=['delete-snapshot', 'ds'],
            description='Remove LVM snapshot of a resource')
        p_rmsnap.add_argument('-f', '--force', action="store_true")
        p_rmsnap.add_argument(
            'resource', type=check_res_name,
            help='Name of the resource').completer = ResourceCommands.completer
        p_rmsnap.add_argument(
            'snapshot',
            type=check_snaps_name,
            nargs="+",
            help='Name of the snapshot').completer = snaps_completer
        p_rmsnap.set_defaults(func=self.cmd_enoimp)

        # remove-snapshot-assignment
        p_rmsnapas = subp.add_parser(
            'remove-snapshot-assignment',
            aliases=['rsa', 'delete-snapshot-assignment', 'dsa'],
            description='Remove snapshot assignment')
        p_rmsnapas.add_argument('-f', '--force', action="store_true")
        p_rmsnapas.add_argument(
            'resource', type=check_res_name,
            help='Name of the resource').completer = ResourceCommands.completer
        p_rmsnapas.add_argument(
            'snapshot', type=check_snaps_name,
            help='Name of the snapshot').completer = snaps_completer
        p_rmsnapas.add_argument(
            'node', type=check_node_name,
            help='Name of the node').completer = NodeCommands.completer
        p_rmsnapas.set_defaults(func=self.cmd_enoimp)

        # restore-snapshot
        p_restsnap = subp.add_parser('restore-snapshot',
                                     aliases=['rs'],
                                     description='Restore snapshot')
        p_restsnap.add_argument(
            'resource',
            type=check_res_name,
            help=
            'Name of the new resource that gets created from existing snapshot'
        )
        p_restsnap.add_argument('snapshot_resource',
                                type=check_res_name,
                                help='Name of the resource that was snapshoted'
                                ).completer = ResourceCommands.completer
        p_restsnap.add_argument(
            'snapshot', type=check_snaps_name,
            help='Name of the snapshot').completer = snaps_completer
        p_restsnap.set_defaults(func=self.cmd_enoimp)

        # resume-all
        p_resume_all = subp.add_parser(
            'resume-all', description="Resumes all failed assignments")
        p_resume_all.set_defaults(func=self.cmd_enoimp)

        def shutdown_restart(command, description, func, aliases=False):
            if aliases:
                p_cmd = subp.add_parser(command,
                                        aliases=aliases,
                                        description=description)
            else:
                p_cmd = subp.add_parser(command, description=description)
            p_cmd.add_argument(
                '-l',
                '--satellite',
                action="store_true",
                help=
                'If given, also send a shutdown command to connected satellites.',
                default=False)
            p_cmd.add_argument(
                '-q',
                '--quiet',
                action="store_true",
                help=
                'Unless this option is used, linstor will issue a safety question '
                'that must be answered with yes, otherwise the operation is canceled.'
            )
            p_cmd.add_argument(
                '-r',
                '--resources',
                action="store_true",
                help='Shutdown all linstor-controlled resources too',
                default=False)
            p_cmd.add_argument('-c',
                               '--ctrlvol',
                               action="store_true",
                               help='Do not drbdadm down the control volume',
                               default=False)
            p_cmd.set_defaults(func=func)

        # shutdown
        shutdown_restart('shutdown',
                         description='Stops the local linstor server process.',
                         func=self.cmd_enoimp)
        # restart
        shutdown_restart(
            'restart',
            description='Restarts the local linstor server process.',
            func=self.cmd_enoimp)

        # snapshots
        snapgroupby = ("Resource", "Name", "State")
        snap_group_completer = Commands.show_group_completer(
            snapgroupby, "groupby")

        p_lsnaps = subp.add_parser('list-snapshots',
                                   aliases=['s', 'snapshots'],
                                   description='List available snapshots')
        p_lsnaps.add_argument('-p',
                              '--pastable',
                              action="store_true",
                              help='Generate pastable output')
        p_lsnaps.add_argument(
            '-g', '--groupby', nargs='+',
            choices=snapgroupby).completer = snap_group_completer
        p_lsnaps.add_argument('-R',
                              '--resources',
                              nargs='+',
                              type=check_res_name,
                              help='Filter by list of resources'
                              ).completer = ResourceCommands.completer
        p_lsnaps.set_defaults(func=self.cmd_enoimp)

        # snapshot-assignments
        snapasgroupby = ("Resource", "Name", "Node", "State")

        snapas_group_completer = Commands.show_group_completer(
            snapasgroupby, "groupby")

        p_lsnapas = subp.add_parser('list-snapshot-assignments',
                                    aliases=['sa', 'snapshot-assignments'],
                                    description='List snapshot assignments')
        p_lsnapas.add_argument('-p',
                               '--pastable',
                               action="store_true",
                               help='Generate pastable output')
        p_lsnapas.add_argument(
            '-g', '--groupby', nargs='+',
            choices=snapasgroupby).completer = snapas_group_completer
        p_lsnapas.add_argument(
            '-N',
            '--nodes',
            nargs='+',
            type=check_node_name,
            help='Filter by list of nodes').completer = NodeCommands.completer
        p_lsnapas.add_argument('-R',
                               '--resources',
                               nargs='+',
                               type=check_res_name,
                               help='Filter by list of resources'
                               ).completer = ResourceCommands.completer
        p_lsnapas.set_defaults(func=self.cmd_enoimp)

        # export
        def exportnamecheck(name):
            if name == '*':
                return name
            return check_res_name(name)

        p_export = subp.add_parser(
            'export-res',
            aliases=['export'],
            description='Exports the configuration files of the specified '
            'linstor resource for use with drbdadm. If "*" is used as '
            'resource name, the configuration files of all linstor resources '
            'deployed on the local node are exported. The configuration files will '
            'be created (or updated) in the linstor directory for temporary '
            'configuration files, typically /var/lib/drbd.d.')
        p_export.add_argument(
            'resource',
            nargs="+",
            type=exportnamecheck,
            help='Name of the resource').completer = ResourceCommands.completer
        p_export.set_defaults(func=self.cmd_enoimp)

        # free-port-nr
        p_free_port_nr = subp.add_parser(
            'free-port-nr',
            description='Find an unallocated TCP/IP port number')
        p_free_port_nr.set_defaults(func=self.cmd_enoimp)

        # free-minor-nr
        p_free_minor_nr = subp.add_parser(
            'free-minor-nr', description='Find an unallocated minor number')
        p_free_minor_nr.set_defaults(func=self.cmd_enoimp)

        # query-port-nr
        p_query_port_nr = subp.add_parser(
            'query-port-nr',
            description='Query the allocation status of a TCP/IP port number')
        p_query_port_nr.add_argument('port', help='TCP/IP port number')
        p_query_port_nr.set_defaults(func=self.cmd_enoimp)

        # query-minor-nr
        p_query_minor_nr = subp.add_parser(
            'query-minor-nr',
            description='Query the allocation status of a minor number')
        p_query_minor_nr.add_argument('minor', help='Device file minor number')
        p_query_minor_nr.set_defaults(func=self.cmd_enoimp)

        # server-version
        p_server_version = subp.add_parser(
            'server-version',
            description='Queries version information from the linstor server')
        p_server_version.set_defaults(func=self.cmd_enoimp)

        # message-log
        p_message_log = subp.add_parser(
            'list-message-log',
            aliases=['message-log', 'list-ml', 'ml'],
            description='Queries the server\'s message log')
        p_message_log.set_defaults(func=self.cmd_enoimp)

        # clear-message-log
        p_message_log = subp.add_parser(
            'clear-message-log',
            aliases=['clear-ml', 'cml'],
            description='Queries the server\'s message log')
        p_message_log.set_defaults(func=self.cmd_enoimp)

        # query-conf
        p_queryconf = subp.add_parser('query-conf',
                                      description='Print the DRBD'
                                      ' configuration file for a given'
                                      ' resource on a given node')
        p_queryconf.add_argument(
            'node', type=check_node_name,
            help='Name of the node').completer = NodeCommands.completer
        p_queryconf.add_argument(
            'resource', type=check_res_name,
            help='Name of the resource').completer = ResourceCommands.completer
        p_queryconf.set_defaults(func=self.cmd_enoimp)

        # ping
        p_ping = subp.add_parser('ping',
                                 description='Pings the server. The '
                                 'server should answer with a "Pong"')
        p_ping.set_defaults(func=self.cmd_ping)

        # initcv
        p_join = subp.add_parser('initcv',
                                 description='Initialize control volume')
        p_join.add_argument('-q', '--quiet', action="store_true")
        p_join.add_argument('dev', help='Path to the control volume')
        p_join.set_defaults(func=self.cmd_enoimp)

        # debug
        p_debug = subp.add_parser('debug')
        p_debug.add_argument('cmd')
        p_debug.set_defaults(func=self.cmd_enoimp)

        # drbd options
        drbd_options = DrbdOptions()
        drbd_options.setup_commands(subp)

        # handlers
        # currently we do not parse the xml-output because drbd-utils are not ready for it
        # number and handler names are very static, so use a list for now and add this feature to
        # drbd-utils later
        handlers = (
            'after-resync-target',
            'before-resync-target',
            'fence-peer',
            'initial-split-brain',
            'local-io-error',
            'pri-lost',
            'pri-lost-after-sb',
            'pri-on-incon-degr',
            'split-brain',
        )
        p_handlers = subp.add_parser(
            'handlers', description='Set or unset event handlers.')
        p_handlers.add_argument('--common', action="store_true")
        p_handlers.add_argument('--resource',
                                type=check_res_name,
                                help='Name of the resource to modify'
                                ).completer = ResourceCommands.completer
        for handler in handlers:
            p_handlers.add_argument('--' + handler,
                                    help='Please refer to drbd.conf(5)',
                                    metavar='cmd')
            p_handlers.add_argument('--unset-' + handler, action='store_true')
        p_handlers.set_defaults(func=self.cmd_enoimp)

        # list-options
        p_listopts = subp.add_parser('list-options',
                                     description='List drbd options set',
                                     aliases=['show-options'])
        p_listopts.add_argument('resource',
                                type=check_res_name,
                                help='Name of the resource to show'
                                ).completer = ResourceCommands.completer
        p_listopts.set_defaults(func=self.cmd_enoimp)
        # p_listopts.set_defaults(doobj=do)
        # p_listopts.set_defaults(noobj=no)
        # p_listopts.set_defaults(roobj=ro)
        # p_listopts.set_defaults(pdoobj=pdo)

        # edit config
        p_editconf = subp.add_parser(
            'modify-config',
            description='Modify linstor configuration',
            aliases=['edit-config'])
        p_editconf.add_argument(
            '--node',
            '-n',
            type=check_node_name,
            help='Name of the node. This enables node specific options '
            '(e.g. plugin settings)').completer = NodeCommands.completer
        p_editconf.set_defaults(func=self.cmd_enoimp)
        p_editconf.set_defaults(type="edit")

        # export config
        p_exportconf = subp.add_parser(
            'export-config',
            description='Export linstor configuration',
            aliases=['cat-config'])
        p_exportconf.add_argument(
            '--node', '-n', type=check_node_name,
            help='Name of the node.').completer = NodeCommands.completer
        p_exportconf.add_argument('--file',
                                  '-f',
                                  help='File to save configuration')
        p_exportconf.set_defaults(func=self.cmd_enoimp)
        p_exportconf.set_defaults(type="export")

        # export ctrl-vol
        p_exportctrlvol = subp.add_parser(
            'export-ctrlvol',
            description='Export linstor control volume as json blob')
        p_exportctrlvol.add_argument(
            '--file',
            '-f',
            help='File to save configuration json blob, if not given: stdout')
        p_exportctrlvol.set_defaults(func=self.cmd_enoimp)

        # import ctrl-vol
        p_importctrlvol = subp.add_parser(
            'import-ctrlvol',
            description='Import linstor control volume from json blob')
        p_importctrlvol.add_argument(
            '-q',
            '--quiet',
            action="store_true",
            help='Unless this option is used, linstor will issue a safety '
            'question that must be answered with yes, otherwise the operation '
            'is canceled.')
        p_importctrlvol.add_argument(
            '--file',
            '-f',
            help='File to load configuration json blob, if not given: stdin')
        p_importctrlvol.set_defaults(func=self.cmd_enoimp)

        # role
        p_role = subp.add_parser(
            'role',
            description=
            'Show role of local linstor (controlnode/satellite/unknown)')
        p_role.set_defaults(func=self.cmd_enoimp)

        # reelect
        p_reelect = subp.add_parser(
            'reelect',
            description='Reelect leader. DO NOT USE this command '
            'if you do not understand all implications!')
        p_reelect.add_argument(
            '--force-win',
            action='store_true',
            help='This is a last resort command to bring up a single leader '
            'in order to get access to the control volume (e.g. remove node '
            'in 2 node cluster)')
        p_reelect.set_defaults(func=self.cmd_enoimp)

        argcomplete.autocomplete(parser)

        return parser