Commit 9c784fb3 authored by Dimitris Aragiorgis's avatar Dimitris Aragiorgis Committed by Iustin Pop
Browse files

Introduce client support for networks



gnt-network is used to manipulate and handle networks that currently
provides the following operations:

 * Add a new network:
   gnt-network add --network=1.2.3.0/28 --gateway=1.2.3.1
                   --add-reserved-ips=1.2.3.4,1.2.3.5 testnet

 * Remove an existing network:
   gnt-network remove testnet

 * Modify an existing network:
   gnt-network modify --gateway=1.2.3.6
                      --network-type=private
                      --network6=2001:648::/64
                      --gateway6=none testnet
                      --add-reserved-ips=1.2.3.10,1.2.3.10,
                      --remove-reserved-ips=1.2.3.20
                      testnet

 * Connect an existing network to a nodegroup:
   gnt-network connect testnet default bridged br100
   gnt-network connect testnet <nodegroup> <mode> <link>
   (pass all for <nodegroup> to connect to all nodegroups)

 * Disconnect an existing network from a nodegroup:
   gnt-network disconnect testnet <nodegroup>
   (pass all for <nodegroup> to disconnect from all nodegroups)

 * List available networks:
   gnt-network list

 * Show network info:
   gnt-network info [testnet]

Introduce new option NOCONFLICTSCHECK_OPT for not checking for
conflicting IPs. Using this might cause data inconsistency.
Signed-off-by: default avatarApollon Oikonomopoulos <apollon@noc.grnet.gr>
Signed-off-by: default avatarDimitris Aragiorgis <dimara@grnet.gr>
Reviewed-by: default avatarIustin Pop <iustin@google.com>
parent d4117a72
......@@ -54,6 +54,7 @@ __all__ = [
# Command line options
"ABSOLUTE_OPT",
"ADD_UIDS_OPT",
"ADD_RESERVED_IPS_OPT",
"ALLOCATABLE_OPT",
"ALLOC_POLICY_OPT",
"ALL_OPT",
......@@ -87,6 +88,8 @@ __all__ = [
"FORCE_FILTER_OPT",
"FORCE_OPT",
"FORCE_VARIANT_OPT",
"GATEWAY_OPT",
"GATEWAY6_OPT",
"GLOBAL_FILEDIR_OPT",
"HID_OS_OPT",
"GLOBAL_SHARED_FILEDIR_OPT",
......@@ -111,6 +114,9 @@ __all__ = [
"MC_OPT",
"MIGRATION_MODE_OPT",
"NET_OPT",
"NETWORK_OPT",
"NETWORK6_OPT",
"NETWORK_TYPE_OPT",
"NEW_CLUSTER_CERT_OPT",
"NEW_CLUSTER_DOMAIN_SECRET_OPT",
"NEW_CONFD_HMAC_KEY_OPT",
......@@ -118,6 +124,7 @@ __all__ = [
"NEW_SECONDARY_OPT",
"NEW_SPICE_CERT_OPT",
"NIC_PARAMS_OPT",
"NOCONFLICTSCHECK_OPT",
"NODE_FORCE_JOIN_OPT",
"NODE_LIST_OPT",
"NODE_PLACEMENT_OPT",
......@@ -160,6 +167,7 @@ __all__ = [
"READD_OPT",
"REBOOT_TYPE_OPT",
"REMOVE_INSTANCE_OPT",
"REMOVE_RESERVED_IPS_OPT",
"REMOVE_UIDS_OPT",
"RESERVED_LVS_OPT",
"RUNTIME_MEM_OPT",
......@@ -236,11 +244,13 @@ __all__ = [
"ARGS_MANY_INSTANCES",
"ARGS_MANY_NODES",
"ARGS_MANY_GROUPS",
"ARGS_MANY_NETWORKS",
"ARGS_NONE",
"ARGS_ONE_INSTANCE",
"ARGS_ONE_NODE",
"ARGS_ONE_GROUP",
"ARGS_ONE_OS",
"ARGS_ONE_NETWORK",
"ArgChoice",
"ArgCommand",
"ArgFile",
......@@ -248,6 +258,7 @@ __all__ = [
"ArgHost",
"ArgInstance",
"ArgJobId",
"ArgNetwork",
"ArgNode",
"ArgOs",
"ArgSuggest",
......@@ -258,6 +269,7 @@ __all__ = [
"OPT_COMPL_ONE_INSTANCE",
"OPT_COMPL_ONE_NODE",
"OPT_COMPL_ONE_NODEGROUP",
"OPT_COMPL_ONE_NETWORK",
"OPT_COMPL_ONE_OS",
"cli_option",
"SplitNodeOption",
......@@ -356,6 +368,11 @@ class ArgNode(_Argument):
"""
class ArgNetwork(_Argument):
"""Network argument.
"""
class ArgGroup(_Argument):
"""Node group argument.
......@@ -394,9 +411,11 @@ class ArgOs(_Argument):
ARGS_NONE = []
ARGS_MANY_INSTANCES = [ArgInstance()]
ARGS_MANY_NETWORKS = [ArgNetwork()]
ARGS_MANY_NODES = [ArgNode()]
ARGS_MANY_GROUPS = [ArgGroup()]
ARGS_ONE_INSTANCE = [ArgInstance(min=1, max=1)]
ARGS_ONE_NETWORK = [ArgNetwork(min=1, max=1)]
ARGS_ONE_NODE = [ArgNode(min=1, max=1)]
# TODO
ARGS_ONE_GROUP = [ArgGroup(min=1, max=1)]
......@@ -640,8 +659,9 @@ def check_maybefloat(option, opt, value): # pylint: disable=W0613
OPT_COMPL_ONE_INSTANCE,
OPT_COMPL_ONE_OS,
OPT_COMPL_ONE_IALLOCATOR,
OPT_COMPL_ONE_NETWORK,
OPT_COMPL_INST_ADD_NODES,
OPT_COMPL_ONE_NODEGROUP) = range(100, 107)
OPT_COMPL_ONE_NODEGROUP) = range(100, 108)
OPT_COMPL_ALL = frozenset([
OPT_COMPL_MANY_NODES,
......@@ -649,6 +669,7 @@ OPT_COMPL_ALL = frozenset([
OPT_COMPL_ONE_INSTANCE,
OPT_COMPL_ONE_OS,
OPT_COMPL_ONE_IALLOCATOR,
OPT_COMPL_ONE_NETWORK,
OPT_COMPL_INST_ADD_NODES,
OPT_COMPL_ONE_NODEGROUP,
])
......@@ -1457,6 +1478,44 @@ ABSOLUTE_OPT = cli_option("--absolute", dest="absolute",
help="Marks the grow as absolute instead of the"
" (default) relative mode")
NETWORK_OPT = cli_option("--network",
action="store", default=None, dest="network",
help="IP network in CIDR notation")
GATEWAY_OPT = cli_option("--gateway",
action="store", default=None, dest="gateway",
help="IP address of the router (gateway)")
ADD_RESERVED_IPS_OPT = cli_option("--add-reserved-ips",
action="store", default=None,
dest="add_reserved_ips",
help="Comma-separated list of"
" reserved IPs to add")
REMOVE_RESERVED_IPS_OPT = cli_option("--remove-reserved-ips",
action="store", default=None,
dest="remove_reserved_ips",
help="Comma-delimited list of"
" reserved IPs to remove")
NETWORK_TYPE_OPT = cli_option("--network-type",
action="store", default=None, dest="network_type",
help="Network type: private, public, None")
NETWORK6_OPT = cli_option("--network6",
action="store", default=None, dest="network6",
help="IP network in CIDR notation")
GATEWAY6_OPT = cli_option("--gateway6",
action="store", default=None, dest="gateway6",
help="IP6 address of the router (gateway)")
NOCONFLICTSCHECK_OPT = cli_option("--no-conflicts-check",
dest="conflicts_check",
default=True,
action="store_false",
help="Don't check for conflicting IPs")
#: Options provided by all commands
COMMON_OPTS = [DEBUG_OPT]
......@@ -1473,6 +1532,7 @@ COMMON_CREATE_OPTS = [
NET_OPT,
NODE_PLACEMENT_OPT,
NOIPCHECK_OPT,
NOCONFLICTSCHECK_OPT,
NONAMECHECK_OPT,
NONICS_OPT,
NWSYNC_OPT,
......
......@@ -1338,6 +1338,7 @@ def SetInstanceParams(opts, args):
force=opts.force,
wait_for_sync=opts.wait_for_sync,
offline=offline,
conflicts_check=opts.conflicts_check,
ignore_ipolicy=opts.ignore_ipolicy)
# even if here we process the result, we allow submit only
......@@ -1527,7 +1528,8 @@ commands = {
[BACKEND_OPT, DISK_OPT, FORCE_OPT, HVOPTS_OPT, NET_OPT, SUBMIT_OPT,
DISK_TEMPLATE_OPT, SINGLE_NODE_OPT, OS_OPT, FORCE_VARIANT_OPT,
OSPARAMS_OPT, DRY_RUN_OPT, PRIORITY_OPT, NWSYNC_OPT, OFFLINE_INST_OPT,
ONLINE_INST_OPT, IGNORE_IPOLICY_OPT, RUNTIME_MEM_OPT],
ONLINE_INST_OPT, IGNORE_IPOLICY_OPT, RUNTIME_MEM_OPT,
NOCONFLICTSCHECK_OPT],
"<instance>", "Alters the parameters of an instance"),
"shutdown": (
GenericManyOps("shutdown", _ShutdownInstance), [ArgInstance()],
......
#
#
# Copyright (C) 2011 Google Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.
"""IP pool related commands"""
# pylint: disable-msg=W0401,W0614
# W0401: Wildcard import ganeti.cli
# W0614: Unused import %s from wildcard import (since we need cli)
from ganeti.cli import *
from ganeti import constants
from ganeti import opcodes
from ganeti import utils
from textwrap import wrap
#: default list of fields for L{ListNetworks}
_LIST_DEF_FIELDS = ["name", "network", "gateway", "group_cnt", "group_list"]
def _HandleReservedIPs(ips):
if ips is not None:
if ips == "":
return []
else:
return utils.UnescapeAndSplit(ips, sep=",")
return None
def AddNetwork(opts, args):
"""Add a network to the cluster.
@param opts: the command line options selected by the user
@type args: list
@param args: a list of length 1 with the network name to create
@rtype: int
@return: the desired exit code
"""
(network_name, ) = args
op = opcodes.OpNetworkAdd(network_name=network_name,
gateway=opts.gateway,
network=opts.network,
gateway6=opts.gateway6,
network6=opts.network6,
mac_prefix=opts.mac_prefix,
network_type=opts.network_type,
add_reserved_ips=_HandleReservedIPs(opts.add_reserved_ips))
SubmitOpCode(op, opts=opts)
def MapNetwork(opts, args):
"""Map a network to a node group.
@param opts: the command line options selected by the user
@type args: list
@param args: a list of length 3 with network, nodegroup, mode, physlink
@rtype: int
@return: the desired exit code
"""
network = args[0]
groups = args[1]
mode = args[2]
link = args[3]
#TODO: allow comma separated group names
if groups == 'all':
cl = GetClient()
(groups, ) = cl.QueryGroups([], ['name'], False)
else:
groups = [groups]
for group in groups:
op = opcodes.OpNetworkConnect(group_name=group,
network_name=network,
network_mode=mode,
network_link=link,
conflicts_check=opts.conflicts_check)
SubmitOpCode(op, opts=opts)
def UnmapNetwork(opts, args):
"""Unmap a network from a node group.
@param opts: the command line options selected by the user
@type args: list
@param args: a list of length 3 with network, nodegorup
@rtype: int
@return: the desired exit code
"""
network = args[0]
groups = args[1]
#TODO: allow comma separated group names
if groups == 'all':
cl = GetClient()
(groups, ) = cl.QueryGroups([], ['name'], False)
else:
groups = [groups]
for group in groups:
op = opcodes.OpNetworkDisconnect(group_name=group,
network_name=network,
conflicts_check=opts.conflicts_check)
SubmitOpCode(op, opts=opts)
def ListNetworks(opts, args):
"""List Ip pools and their properties.
@param opts: the command line options selected by the user
@type args: list
@param args: networks to list, or empty for all
@rtype: int
@return: the desired exit code
"""
desired_fields = ParseFields(opts.output, _LIST_DEF_FIELDS)
fmtoverride = {
"group_list": (",".join, False),
"inst_list": (",".join, False),
}
return GenericList(constants.QR_NETWORK, desired_fields, args, None,
opts.separator, not opts.no_headers,
verbose=opts.verbose, format_override=fmtoverride)
def ListNetworkFields(opts, args):
"""List network fields.
@param opts: the command line options selected by the user
@type args: list
@param args: fields to list, or empty for all
@rtype: int
@return: the desired exit code
"""
return GenericListFields(constants.QR_NETWORK, args, opts.separator,
not opts.no_headers)
def ShowNetworkConfig(opts, args):
"""Show network information.
@param opts: the command line options selected by the user
@type args: list
@param args: should either be an empty list, in which case
we show information about all nodes, or should contain
a list of networks (names or UUIDs) to be queried for information
@rtype: int
@return: the desired exit code
"""
cl = GetClient()
result = cl.QueryNetworks(fields=["name", "network", "gateway",
"network6", "gateway6",
"mac_prefix", "network_type",
"free_count", "reserved_count",
"map", "group_list", "inst_list",
"external_reservations"],
names=args, use_locking=False)
for (name, network, gateway, network6, gateway6,
mac_prefix, network_type, free_count, reserved_count,
map, group_list, instances, ext_res) in result:
size = free_count + reserved_count
ToStdout("Network name: %s", name)
ToStdout(" subnet: %s", network)
ToStdout(" gateway: %s", gateway)
ToStdout(" subnet6: %s", network6)
ToStdout(" gateway6: %s", gateway6)
ToStdout(" mac prefix: %s", mac_prefix)
ToStdout(" type: %s", network_type)
ToStdout(" size: %d", size)
ToStdout(" free: %d (%.2f%%)", free_count,
100 * float(free_count)/float(size))
ToStdout(" usage map:")
idx = 0
for line in wrap(map, width=64):
ToStdout(" %s %s %d", str(idx).rjust(3), line.ljust(64), idx + 63)
idx += 64
ToStdout(" (X) used (.) free")
if ext_res:
ToStdout(" externally reserved IPs:")
for line in wrap(ext_res, width=64):
ToStdout(" %s" % line)
if group_list:
ToStdout(" connected to node groups:")
for group in group_list:
ToStdout(" %s", group)
else:
ToStdout(" not connected to any node group")
if instances:
ToStdout(" used by %d instances:", len(instances))
for inst in instances:
((ips, networks), ) = cl.QueryInstances([inst],
["nic.ips", "nic.networks"],
use_locking=False)
l = lambda value: ", ".join(`idx`+":"+str(ip)
for idx, (ip, net) in enumerate(value)
if net == name)
ToStdout(" %s : %s", inst, l(zip(ips,networks)))
else:
ToStdout(" not used by any instances")
def SetNetworkParams(opts, args):
"""Modifies an IP address pool's parameters.
@param opts: the command line options selected by the user
@type args: list
@param args: should contain only one element, the node group name
@rtype: int
@return: the desired exit code
"""
# TODO: add "network": opts.network,
all_changes = {
"gateway": opts.gateway,
"add_reserved_ips": _HandleReservedIPs(opts.add_reserved_ips),
"remove_reserved_ips": _HandleReservedIPs(opts.remove_reserved_ips),
"mac_prefix": opts.mac_prefix,
"network_type": opts.network_type,
"gateway6": opts.gateway6,
"network6": opts.network6,
}
if all_changes.values().count(None) == len(all_changes):
ToStderr("Please give at least one of the parameters.")
return 1
op = opcodes.OpNetworkSetParams(network_name=args[0],
# pylint: disable-msg=W0142
**all_changes)
# TODO: add feedback to user, e.g. list the modifications
SubmitOrSend(op, opts)
def RemoveNetwork(opts, args):
"""Remove an IP address pool from the cluster.
@param opts: the command line options selected by the user
@type args: list
@param args: a list of length 1 with the id of the IP address pool to remove
@rtype: int
@return: the desired exit code
"""
(network_name,) = args
op = opcodes.OpNetworkRemove(network_name=network_name, force=opts.force)
SubmitOpCode(op, opts=opts)
commands = {
"add": (
AddNetwork, ARGS_ONE_NETWORK,
[DRY_RUN_OPT, NETWORK_OPT, GATEWAY_OPT, ADD_RESERVED_IPS_OPT,
MAC_PREFIX_OPT, NETWORK_TYPE_OPT, NETWORK6_OPT, GATEWAY6_OPT],
"<network_name>", "Add a new IP network to the cluster"),
"list": (
ListNetworks, ARGS_MANY_NETWORKS,
[NOHDR_OPT, SEP_OPT, FIELDS_OPT, VERBOSE_OPT],
"[<network_id>...]",
"Lists the IP networks in the cluster. The available fields can be shown"
" using the \"list-fields\" command (see the man page for details)."
" The default list is (in order): %s." % utils.CommaJoin(_LIST_DEF_FIELDS)),
"list-fields": (
ListNetworkFields, [ArgUnknown()], [NOHDR_OPT, SEP_OPT], "[fields...]",
"Lists all available fields for networks"),
"info": (
ShowNetworkConfig, ARGS_MANY_NETWORKS, [],
"[<network_name>...]", "Show information about the network(s)"),
"modify": (
SetNetworkParams, ARGS_ONE_NETWORK,
[DRY_RUN_OPT, SUBMIT_OPT, ADD_RESERVED_IPS_OPT, REMOVE_RESERVED_IPS_OPT,
GATEWAY_OPT, MAC_PREFIX_OPT, NETWORK_TYPE_OPT, NETWORK6_OPT, GATEWAY6_OPT],
"<network_name>", "Alters the parameters of a network"),
"connect": (
MapNetwork,
[ArgNetwork(min=1, max=1), ArgGroup(min=1, max=1),
ArgUnknown(min=1, max=1), ArgUnknown(min=1, max=1)],
[NOCONFLICTSCHECK_OPT],
"<network_name> <node_group> <mode> <link>",
"Map a given network to the specified node group"
" with given mode and link (netparams)"),
"disconnect": (
UnmapNetwork,
[ArgNetwork(min=1, max=1), ArgGroup(min=1, max=1)],
[NOCONFLICTSCHECK_OPT],
"<network_name> <node_group>",
"Unmap a given network from a specified node group"),
"remove": (
RemoveNetwork, ARGS_ONE_NETWORK, [FORCE_OPT, DRY_RUN_OPT],
"[--dry-run] <network_id>",
"Remove an (empty) network from the cluster"),
}
def Main():
return GenericMain(commands)
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment