PR#2933: Enable/disable channel
Merges #2933 https://pagure.io/koji/pull-request/2933 Fixes: #1851 https://pagure.io/koji/issue/1851 [RFE] disable channel
This commit is contained in:
commit
cfcf900e25
23 changed files with 659 additions and 80 deletions
|
|
@ -45,7 +45,8 @@ from koji_cli.lib import (
|
|||
unique_path,
|
||||
warn,
|
||||
watch_logs,
|
||||
watch_tasks
|
||||
watch_tasks,
|
||||
truncate_string
|
||||
)
|
||||
|
||||
try:
|
||||
|
|
@ -254,6 +255,7 @@ def handle_add_host_to_channel(goptions, session, args):
|
|||
parser = OptionParser(usage=get_usage_str(usage))
|
||||
parser.add_option("--list", action="store_true", help=SUPPRESS_HELP)
|
||||
parser.add_option("--new", action="store_true", help=_("Create channel if needed"))
|
||||
parser.add_option("--force", action="store_true", help=_("force added, if possible"))
|
||||
(options, args) = parser.parse_args(args)
|
||||
if not options.list and len(args) != 2:
|
||||
parser.error(_("Please specify a hostname and a channel"))
|
||||
|
|
@ -267,6 +269,7 @@ def handle_add_host_to_channel(goptions, session, args):
|
|||
channelinfo = session.getChannel(channel)
|
||||
if not channelinfo:
|
||||
error("No such channel: %s" % channel)
|
||||
|
||||
host = args[0]
|
||||
hostinfo = session.getHost(host)
|
||||
if not hostinfo:
|
||||
|
|
@ -274,6 +277,8 @@ def handle_add_host_to_channel(goptions, session, args):
|
|||
kwargs = {}
|
||||
if options.new:
|
||||
kwargs['create'] = True
|
||||
if options.force:
|
||||
kwargs['force'] = True
|
||||
session.addHostToChannel(host, channel, **kwargs)
|
||||
|
||||
|
||||
|
|
@ -348,11 +353,73 @@ def handle_edit_channel(goptions, session, args):
|
|||
parser = OptionParser(usage=get_usage_str(usage))
|
||||
parser.add_option("--name", help=_("New channel name"))
|
||||
parser.add_option("--description", help=_("Description of channel"))
|
||||
parser.add_option("--comment", help=_("Comment of channel"))
|
||||
(options, args) = parser.parse_args(args)
|
||||
if len(args) != 1:
|
||||
parser.error(_("Incorrect number of arguments"))
|
||||
activate_session(session, goptions)
|
||||
session.editChannel(args[0], name=options.name, description=options.description)
|
||||
vals = {}
|
||||
for key, val in options.__dict__.items():
|
||||
if val is not None:
|
||||
vals[key] = val
|
||||
cinfo = session.getChannel(args[0])
|
||||
if not cinfo:
|
||||
error("No such channel: %s" % args[0])
|
||||
result = session.editChannel(args[0], **vals)
|
||||
if not result:
|
||||
error(_("No changes made, please correct the command line"))
|
||||
|
||||
|
||||
def handle_enable_channel(goptions, session, args):
|
||||
"[admin] Mark one or more channels as enabled"
|
||||
usage = _("usage: %prog enable-channel [options] <channelname> [<channelname> ...]")
|
||||
parser = OptionParser(usage=get_usage_str(usage))
|
||||
parser.add_option("--comment", help=_("Comment indicating why the channel(s) are being "
|
||||
"enabled"))
|
||||
(options, args) = parser.parse_args(args)
|
||||
|
||||
if not args:
|
||||
parser.error(_("At least one channel must be specified"))
|
||||
|
||||
activate_session(session, goptions)
|
||||
with session.multicall() as m:
|
||||
result = [m.getChannel(channel, strict=False) for channel in args]
|
||||
error_hit = False
|
||||
for channel, id in zip(args, result):
|
||||
if not id.result:
|
||||
print("No such channel: %s" % channel)
|
||||
error_hit = True
|
||||
if error_hit:
|
||||
error("No changes made. Please correct the command line.")
|
||||
|
||||
with session.multicall() as m:
|
||||
[m.enableChannel(channel, comment=options.comment) for channel in args]
|
||||
|
||||
|
||||
def handle_disable_channel(goptions, session, args):
|
||||
"[admin] Mark one or more channels as disabled"
|
||||
usage = _("usage: %prog disable-channel [options] <channelname> [<channelname> ...]")
|
||||
parser = OptionParser(usage=get_usage_str(usage))
|
||||
parser.add_option("--comment", help=_("Comment indicating why the channel(s) are being "
|
||||
"disabled"))
|
||||
(options, args) = parser.parse_args(args)
|
||||
|
||||
if not args:
|
||||
parser.error(_("At least one channel must be specified"))
|
||||
|
||||
activate_session(session, goptions)
|
||||
|
||||
with session.multicall() as m:
|
||||
result = [m.getChannel(channel, strict=False) for channel in args]
|
||||
error_hit = False
|
||||
for channel, id in zip(args, result):
|
||||
if not id.result:
|
||||
print("No such channel: %s" % channel)
|
||||
error_hit = True
|
||||
if error_hit:
|
||||
error("No changes made. Please correct the command line.")
|
||||
with session.multicall() as m:
|
||||
[m.disableChannel(channel, comment=options.comment) for channel in args]
|
||||
|
||||
|
||||
def handle_add_pkg(goptions, session, args):
|
||||
|
|
@ -2872,29 +2939,47 @@ def handle_unblock_group_req(goptions, session, args):
|
|||
|
||||
def anon_handle_list_channels(goptions, session, args):
|
||||
"[info] Print channels listing"
|
||||
usage = _("usage: %prog list-channels")
|
||||
usage = _("usage: %prog list-channels [options]")
|
||||
parser = OptionParser(usage=get_usage_str(usage))
|
||||
parser.add_option("--simple", action="store_true", default=False,
|
||||
help=_("Print just list of channels without additional info"))
|
||||
parser.add_option("--quiet", action="store_true", default=goptions.quiet,
|
||||
help=_("Do not print header information"))
|
||||
parser.add_option("--comment", action="store_true", help=_("Show comments"))
|
||||
parser.add_option("--description", action="store_true", help=_("Show descriptions"))
|
||||
parser.add_option("--enabled", action="store_true", help=_("Limit to enabled channels"))
|
||||
parser.add_option("--not-enabled", action="store_false", dest="enabled",
|
||||
help=_("Limit to not enabled channels"))
|
||||
parser.add_option("--disabled", action="store_false", dest="enabled",
|
||||
help=_("Alias for --not-enabled"))
|
||||
(options, args) = parser.parse_args(args)
|
||||
ensure_connection(session, goptions)
|
||||
channels = session.listChannels()
|
||||
channels = sorted(channels, key=lambda x: x['name'])
|
||||
opts = {}
|
||||
if options.enabled is not None:
|
||||
opts['enabled'] = options.enabled
|
||||
channels = sorted([x for x in session.listChannels(**opts)], key=lambda x: x['name'])
|
||||
|
||||
session.multicall = True
|
||||
for channel in channels:
|
||||
session.listHosts(channelID=channel['id'])
|
||||
for channel, [hosts] in zip(channels, session.multiCall()):
|
||||
channel['enabled'] = len([x for x in hosts if x['enabled']])
|
||||
channel['disabled'] = len(hosts) - channel['enabled']
|
||||
channel['enabled_host'] = len([x for x in hosts if x['enabled']])
|
||||
channel['disabled'] = len(hosts) - channel['enabled_host']
|
||||
channel['ready'] = len([x for x in hosts if x['ready']])
|
||||
channel['capacity'] = sum([x['capacity'] for x in hosts])
|
||||
channel['load'] = sum([x['task_load'] for x in hosts])
|
||||
channel['comment'] = truncate_string(channel['comment'])
|
||||
channel['description'] = truncate_string(channel['description'])
|
||||
if channel['capacity']:
|
||||
channel['perc_load'] = channel['load'] / channel['capacity'] * 100.0
|
||||
else:
|
||||
channel['perc_load'] = 0.0
|
||||
if not channel['enabled']:
|
||||
channel['name'] = channel['name'] + ' [disabled]'
|
||||
if channels:
|
||||
longest_channel = max([len(ch['name']) for ch in channels])
|
||||
else:
|
||||
longest_channel = 8
|
||||
if options.simple:
|
||||
if not options.quiet:
|
||||
print('Channel')
|
||||
|
|
@ -2902,10 +2987,22 @@ def anon_handle_list_channels(goptions, session, args):
|
|||
print(channel['name'])
|
||||
else:
|
||||
if not options.quiet:
|
||||
print('Channel Enabled Ready Disbld Load Cap Perc')
|
||||
hdr = '{channame:<{longest_channel}}Enabled Ready Disbld Load Cap ' \
|
||||
'Perc '
|
||||
hdr = hdr.format(longest_channel=longest_channel, channame='Channel')
|
||||
if options.description:
|
||||
hdr += "Description".ljust(53)
|
||||
if options.comment:
|
||||
hdr += "Comment".ljust(53)
|
||||
print(hdr)
|
||||
mask = "%%(name)-%ss %%(enabled_host)6d %%(ready)6d %%(disabled)6d %%(load)6d %%(" \
|
||||
"capacity)6d %%(perc_load)6d%%%%" % longest_channel
|
||||
if options.description:
|
||||
mask += " %(description)-50s"
|
||||
if options.comment:
|
||||
mask += " %(comment)-50s"
|
||||
for channel in channels:
|
||||
print("%(name)-15s %(enabled)6d %(ready)6d %(disabled)6d %(load)6d %(capacity)6d "
|
||||
"%(perc_load)6d%%" % channel)
|
||||
print(mask % channel)
|
||||
|
||||
|
||||
def anon_handle_list_hosts(goptions, session, args):
|
||||
|
|
@ -2954,16 +3051,6 @@ def anon_handle_list_hosts(goptions, session, args):
|
|||
else:
|
||||
return 'N'
|
||||
|
||||
def truncate(s):
|
||||
if s:
|
||||
s = s.replace('\n', ' ')
|
||||
if len(s) > 47:
|
||||
return s[:47] + '...'
|
||||
else:
|
||||
return s
|
||||
else:
|
||||
return ''
|
||||
|
||||
try:
|
||||
first = session.getLastHostUpdate(hosts[0]['id'], ts=True)
|
||||
opts = {'ts': True}
|
||||
|
|
@ -2985,23 +3072,29 @@ def anon_handle_list_hosts(goptions, session, args):
|
|||
host['enabled'] = yesno(host['enabled'])
|
||||
host['ready'] = yesno(host['ready'])
|
||||
host['arches'] = ','.join(host['arches'].split())
|
||||
host['description'] = truncate(host['description'])
|
||||
host['comment'] = truncate(host['comment'])
|
||||
host['description'] = truncate_string(host['description'])
|
||||
host['comment'] = truncate_string(host['comment'])
|
||||
|
||||
# pull hosts' channels
|
||||
if options.show_channels:
|
||||
session.multicall = True
|
||||
for host in hosts:
|
||||
session.listChannels(host['id'])
|
||||
for host, [channels] in zip(hosts, session.multiCall()):
|
||||
host['channels'] = ','.join(sorted([c['name'] for c in channels]))
|
||||
with session.multicall() as m:
|
||||
result = [m.listChannels(host['id']) for host in hosts]
|
||||
for host, channels in zip(hosts, result):
|
||||
list_channels = []
|
||||
for c in channels.result:
|
||||
if c['enabled']:
|
||||
list_channels.append(c['name'])
|
||||
else:
|
||||
list_channels.append('*' + c['name'])
|
||||
host['channels'] = ','.join(sorted(list_channels))
|
||||
|
||||
if hosts:
|
||||
longest_host = max([len(h['name']) for h in hosts])
|
||||
else:
|
||||
longest_host = 8
|
||||
if not options.quiet:
|
||||
hdr = "{hostname:<{longest_host}} Enb Rdy Load/Cap Arches Last Update "
|
||||
hdr = "{hostname:<{longest_host}} Enb Rdy Load/Cap Arches " \
|
||||
"Last Update "
|
||||
hdr = hdr.format(longest_host=longest_host, hostname='Hostname')
|
||||
if options.description:
|
||||
hdr += "Description".ljust(51)
|
||||
|
|
@ -3011,7 +3104,7 @@ def anon_handle_list_hosts(goptions, session, args):
|
|||
hdr += "Channels"
|
||||
print(hdr)
|
||||
mask = "%%(name)-%ss %%(enabled)-3s %%(ready)-3s %%(task_load)4.1f/%%(capacity)-4.1f " \
|
||||
"%%(arches)-16s %%(update)-19s" % longest_host
|
||||
"%%(arches)-16s %%(update)-35s" % longest_host
|
||||
if options.description:
|
||||
mask += " %(description)-50s"
|
||||
if options.comment:
|
||||
|
|
|
|||
|
|
@ -830,3 +830,15 @@ def format_inheritance_flags(parent):
|
|||
else:
|
||||
flags += '.'
|
||||
return flags
|
||||
|
||||
|
||||
def truncate_string(s, length=47):
|
||||
"""Return a truncated string when string length is longer than given length."""
|
||||
if s:
|
||||
s = s.replace('\n', ' ')
|
||||
if len(s) > length:
|
||||
return s[:length] + '...'
|
||||
else:
|
||||
return s
|
||||
else:
|
||||
return ''
|
||||
|
|
|
|||
|
|
@ -5,5 +5,7 @@
|
|||
BEGIN;
|
||||
|
||||
ALTER TABLE channels ADD COLUMN description TEXT;
|
||||
ALTER TABLE channels ADD COLUMN enabled BOOLEAN NOT NULL DEFAULT 'true';
|
||||
ALTER TABLE channels ADD COLUMN comment TEXT;
|
||||
|
||||
COMMIT;
|
||||
|
|
|
|||
|
|
@ -136,7 +136,9 @@ CREATE INDEX sessions_expired ON sessions(expired);
|
|||
CREATE TABLE channels (
|
||||
id SERIAL NOT NULL PRIMARY KEY,
|
||||
name VARCHAR(128) UNIQUE NOT NULL,
|
||||
description TEXT
|
||||
description TEXT,
|
||||
enabled BOOLEAN NOT NULL DEFAULT 'true',
|
||||
comment TEXT
|
||||
) WITHOUT OIDS;
|
||||
|
||||
-- create default channel
|
||||
|
|
|
|||
|
|
@ -2237,7 +2237,7 @@ def set_host_enabled(hostname, enabled=True):
|
|||
insert.execute()
|
||||
|
||||
|
||||
def add_host_to_channel(hostname, channel_name, create=False):
|
||||
def add_host_to_channel(hostname, channel_name, create=False, force=False):
|
||||
"""Add the host to the specified channel
|
||||
|
||||
Channel must already exist unless create option is specified
|
||||
|
|
@ -2250,6 +2250,9 @@ def add_host_to_channel(hostname, channel_name, create=False):
|
|||
channel_id = get_channel_id(channel_name, create=create)
|
||||
if channel_id is None:
|
||||
raise koji.GenericError('channel does not exist: %s' % channel_name)
|
||||
if not force:
|
||||
if not get_channel(channel_id)['enabled']:
|
||||
raise koji.GenericError('channel %s is disabled' % channel_name)
|
||||
channels = list_channels(host_id)
|
||||
for channel in channels:
|
||||
if channel['id'] == channel_id:
|
||||
|
|
@ -2307,33 +2310,41 @@ def rename_channel(old, new):
|
|||
update.execute()
|
||||
|
||||
|
||||
def edit_channel(channelInfo, name=None, description=None):
|
||||
def edit_channel(channelInfo, **kw):
|
||||
"""Edit information for an existing channel.
|
||||
|
||||
:param str/int channelInfo: channel name or ID
|
||||
:param str name: new channel name
|
||||
:param str description: description of channel
|
||||
:param str comment: comment about channel
|
||||
"""
|
||||
context.session.assertPerm('admin')
|
||||
channel = get_channel(channelInfo, strict=True)
|
||||
|
||||
if name:
|
||||
if not isinstance(name, str):
|
||||
fields = ('description', 'comment', 'name')
|
||||
changes = []
|
||||
for field in fields:
|
||||
if field in kw and kw[field] != channel[field]:
|
||||
changes.append(field)
|
||||
|
||||
if not changes:
|
||||
return False
|
||||
|
||||
if kw.get('name'):
|
||||
if not isinstance(kw['name'], str):
|
||||
raise koji.GenericError("new channel name must be a string")
|
||||
dup_check = get_channel(name, strict=False)
|
||||
dup_check = get_channel(kw['name'], strict=False)
|
||||
if dup_check:
|
||||
raise koji.GenericError("channel %(name)s already exists (id=%(id)i)" % dup_check)
|
||||
|
||||
update = UpdateProcessor('channels',
|
||||
values={'channelID': channel['id']},
|
||||
clauses=['id = %(channelID)i'])
|
||||
if name:
|
||||
update.set(name=name)
|
||||
if description:
|
||||
update.set(description=description)
|
||||
for change in changes:
|
||||
update.set(**{change: kw[change]})
|
||||
update.execute()
|
||||
|
||||
return None
|
||||
return True
|
||||
|
||||
|
||||
def remove_channel(channel_name, force=False):
|
||||
|
|
@ -2388,6 +2399,18 @@ def add_channel(channel_name, description=None):
|
|||
return channel_id
|
||||
|
||||
|
||||
def set_channel_enabled(channelname, enabled=True, comment=None):
|
||||
context.session.assertPerm('host')
|
||||
channel = get_channel(channelname)
|
||||
if not channel:
|
||||
raise koji.GenericError('No such channel: %s' % channelname)
|
||||
update = UpdateProcessor('channels', values=channel, clauses=['id = %(id)i'])
|
||||
update.set(enabled=enabled)
|
||||
if comment is not None:
|
||||
update.set(comment=comment)
|
||||
update.execute()
|
||||
|
||||
|
||||
def get_ready_hosts():
|
||||
"""Return information about hosts that are ready to build.
|
||||
|
||||
|
|
@ -5372,7 +5395,7 @@ def get_channel(channelInfo, strict=False):
|
|||
:returns: dict of the channel ID and name, or None.
|
||||
For example, {'id': 20, 'name': 'container'}
|
||||
"""
|
||||
fields = ('id', 'name', 'description')
|
||||
fields = ('id', 'name', 'description', 'enabled', 'comment')
|
||||
query = """SELECT %s FROM channels
|
||||
WHERE """ % ', '.join(fields)
|
||||
if isinstance(channelInfo, int):
|
||||
|
|
@ -5514,7 +5537,7 @@ def get_buildroot(buildrootID, strict=False):
|
|||
return result[0]
|
||||
|
||||
|
||||
def list_channels(hostID=None, event=None):
|
||||
def list_channels(hostID=None, event=None, enabled=None):
|
||||
"""
|
||||
List builder channels.
|
||||
|
||||
|
|
@ -5526,18 +5549,29 @@ def list_channels(hostID=None, event=None):
|
|||
default behavior is to search for the "active" host
|
||||
settings. You must specify a hostID parameter with this
|
||||
option.
|
||||
:param bool enabled: Enabled/disabled list of channels
|
||||
:returns: list of dicts, one per channel. For example,
|
||||
[{'id': 20, 'name': 'container', 'description': 'container channel'}]
|
||||
[{'comment': 'test channel', 'description': 'container channel',
|
||||
'enabled': True, 'id': 20, 'name': 'container', 'container channel' }]
|
||||
"""
|
||||
fields = {'channels.id': 'id', 'channels.name': 'name',
|
||||
'channels.description': 'description'}
|
||||
fields = {'channels.id': 'id', 'channels.name': 'name', 'channels.description': 'description',
|
||||
'channels.enabled': 'enabled', 'channels.comment': 'comment'}
|
||||
columns, aliases = zip(*fields.items())
|
||||
if enabled is not None:
|
||||
if enabled:
|
||||
enable_clause = 'enabled IS TRUE'
|
||||
else:
|
||||
enable_clause = 'enabled IS FALSE'
|
||||
if hostID:
|
||||
if isinstance(hostID, str):
|
||||
hostID = get_host(hostID, strict=True)['id']
|
||||
tables = ['host_channels']
|
||||
joins = ['channels ON channels.id = host_channels.channel_id']
|
||||
clauses = [
|
||||
eventCondition(event, table='host_channels'),
|
||||
'host_channels.host_id = %(host_id)s']
|
||||
if enabled is not None:
|
||||
clauses.append(enable_clause)
|
||||
values = {'host_id': hostID}
|
||||
query = QueryProcessor(tables=tables, aliases=aliases,
|
||||
columns=columns, joins=joins,
|
||||
|
|
@ -5546,8 +5580,12 @@ def list_channels(hostID=None, event=None):
|
|||
raise koji.GenericError('list_channels with event and '
|
||||
'not host is not allowed.')
|
||||
else:
|
||||
if enabled is not None:
|
||||
clauses = [enable_clause]
|
||||
else:
|
||||
clauses = None
|
||||
query = QueryProcessor(tables=['channels'], aliases=aliases,
|
||||
columns=columns)
|
||||
columns=columns, clauses=clauses)
|
||||
return query.execute()
|
||||
|
||||
|
||||
|
|
@ -12643,6 +12681,14 @@ class RootExports(object):
|
|||
"""Mark a host as disabled"""
|
||||
set_host_enabled(hostname, False)
|
||||
|
||||
def enableChannel(self, channelname, comment=None):
|
||||
"""Mark a channel as enabled"""
|
||||
set_channel_enabled(channelname, enabled=True, comment=comment)
|
||||
|
||||
def disableChannel(self, channelname, comment=None):
|
||||
"""Mark a channel as disabled"""
|
||||
set_channel_enabled(channelname, enabled=False, comment=comment)
|
||||
|
||||
getHost = staticmethod(get_host)
|
||||
editHost = staticmethod(edit_host)
|
||||
addHostToChannel = staticmethod(add_host_to_channel)
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ admin commands:
|
|||
block-group-req Block a group's requirement listing
|
||||
block-pkg Block a package in the listing for tag
|
||||
clone-tag Duplicate the contents of one tag onto another tag
|
||||
disable-channel Mark one or more channels as disabled
|
||||
disable-host Mark one or more hosts as disabled
|
||||
disable-user Disable logins by a user
|
||||
edit-channel Edit a channel
|
||||
|
|
@ -29,6 +30,7 @@ admin commands:
|
|||
edit-tag-inheritance Edit tag inheritance
|
||||
edit-target Set the name, build_tag, and/or dest_tag of an existing build target to new values
|
||||
edit-user Alter user information
|
||||
enable-channel Mark one or more channels as enabled
|
||||
enable-host Mark one or more hosts as enabled
|
||||
enable-user Enable logins by a user
|
||||
free-task Free a task
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ admin commands:
|
|||
block-group-req Block a group's requirement listing
|
||||
block-pkg Block a package in the listing for tag
|
||||
clone-tag Duplicate the contents of one tag onto another tag
|
||||
disable-channel Mark one or more channels as disabled
|
||||
disable-host Mark one or more hosts as disabled
|
||||
disable-user Disable logins by a user
|
||||
edit-channel Edit a channel
|
||||
|
|
@ -29,6 +30,7 @@ admin commands:
|
|||
edit-tag-inheritance Edit tag inheritance
|
||||
edit-target Set the name, build_tag, and/or dest_tag of an existing build target to new values
|
||||
edit-user Alter user information
|
||||
enable-channel Mark one or more channels as enabled
|
||||
enable-host Mark one or more hosts as enabled
|
||||
enable-user Enable logins by a user
|
||||
free-task Free a task
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import unittest
|
|||
from koji_cli.commands import handle_add_host_to_channel
|
||||
from . import utils
|
||||
|
||||
|
||||
class TestAddHostToChannel(utils.CliTestCase):
|
||||
|
||||
# Show long diffs in error output...
|
||||
|
|
@ -80,7 +81,6 @@ class TestAddHostToChannel(utils.CliTestCase):
|
|||
channel = 'channel'
|
||||
new_arg = '--new'
|
||||
args = [host, channel, new_arg]
|
||||
kwargs = {'create': True}
|
||||
options = mock.MagicMock()
|
||||
|
||||
# Mock out the xmlrpc server
|
||||
|
|
@ -98,8 +98,7 @@ class TestAddHostToChannel(utils.CliTestCase):
|
|||
activate_session_mock.assert_called_once_with(session, options)
|
||||
session.getChannel.assert_not_called()
|
||||
session.getHost.assert_called_once_with(host)
|
||||
session.addHostToChannel.assert_called_once_with(
|
||||
host, channel, **kwargs)
|
||||
session.addHostToChannel.assert_called_once_with(host, channel, create=True)
|
||||
self.assertNotEqual(rv, 1)
|
||||
|
||||
@mock.patch('sys.stderr', new_callable=six.StringIO)
|
||||
|
|
|
|||
115
tests/test_cli/test_disable_channel.py
Normal file
115
tests/test_cli/test_disable_channel.py
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
import unittest
|
||||
|
||||
import mock
|
||||
import six
|
||||
|
||||
import koji
|
||||
from koji_cli.commands import handle_disable_channel
|
||||
from . import utils
|
||||
|
||||
|
||||
class TestDisableChannel(utils.CliTestCase):
|
||||
# Show long diffs in error output...
|
||||
maxDiff = None
|
||||
|
||||
def setUp(self):
|
||||
self.error_format = """Usage: %s disable-channel [options] <channelname> [<channelname> ...]
|
||||
(Specify the --help global option for a list of other help options)
|
||||
|
||||
%s: error: {message}
|
||||
""" % (self.progname, self.progname)
|
||||
self.channelinfo = [
|
||||
{'comment': None, 'description': None, 'enabled': False, 'id': 1,
|
||||
'name': 'test-channel'}
|
||||
]
|
||||
|
||||
def __vm(self, result):
|
||||
m = koji.VirtualCall('mcall_method', [], {})
|
||||
if isinstance(result, dict) and result.get('faultCode'):
|
||||
m._result = result
|
||||
else:
|
||||
m._result = (result,)
|
||||
return m
|
||||
|
||||
@mock.patch('sys.stderr', new_callable=six.StringIO)
|
||||
@mock.patch('sys.stdout', new_callable=six.StringIO)
|
||||
@mock.patch('koji_cli.commands.activate_session')
|
||||
def test_handle_disable_channel(self, activate_session_mock, stdout, stderr):
|
||||
"""Test disable-channel function"""
|
||||
options = mock.MagicMock()
|
||||
session = mock.MagicMock()
|
||||
|
||||
mcall = session.multicall.return_value.__enter__.return_value
|
||||
|
||||
mcall.getChannel.return_value = self.__vm(None)
|
||||
|
||||
arguments = ['test-channel']
|
||||
with self.assertRaises(SystemExit) as ex:
|
||||
handle_disable_channel(options, session, arguments)
|
||||
self.assertExitCode(ex, 1)
|
||||
activate_session_mock.assert_called_once()
|
||||
session.multicall.assert_called_once()
|
||||
session.disableChannel.assert_not_called()
|
||||
expect = ''
|
||||
for host in arguments:
|
||||
expect += "No such channel: %s\n" % host
|
||||
stderr_exp = "No changes made. Please correct the command line.\n"
|
||||
self.assert_console_message(stdout, expect)
|
||||
self.assert_console_message(stderr, stderr_exp)
|
||||
|
||||
# reset session mocks
|
||||
activate_session_mock.reset_mock()
|
||||
session.disableChannel.reset_mock()
|
||||
session.multicall.reset_mock()
|
||||
mcall = session.multicall.return_value.__enter__.return_value
|
||||
|
||||
mcall.getChannel.return_value = self.__vm(self.channelinfo)
|
||||
|
||||
arguments = ['test-channel', '--comment', 'enable channel test']
|
||||
handle_disable_channel(options, session, arguments)
|
||||
activate_session_mock.assert_called_once()
|
||||
self.assertEqual(2, session.multicall.call_count)
|
||||
self.assert_console_message(stdout, '')
|
||||
|
||||
@mock.patch('sys.stdout', new_callable=six.StringIO)
|
||||
@mock.patch('koji_cli.commands.activate_session')
|
||||
def test_handle_disable_host_no_argument(self, activate_session_mock, stdout):
|
||||
"""Test disable-channel function without arguments"""
|
||||
options = mock.MagicMock()
|
||||
session = mock.MagicMock()
|
||||
|
||||
session.getChannel.return_value = None
|
||||
session.multicall.return_value = [[None]]
|
||||
session.disableChannel.return_value = True
|
||||
|
||||
expected = self.format_error_message("At least one channel must be specified")
|
||||
self.assert_system_exit(
|
||||
handle_disable_channel,
|
||||
options,
|
||||
session,
|
||||
[],
|
||||
stderr=expected,
|
||||
activate_session=None)
|
||||
|
||||
activate_session_mock.assert_not_called()
|
||||
session.getChannel.assert_not_called()
|
||||
session.multicall.assert_not_called()
|
||||
session.disableChannel.assert_not_called()
|
||||
|
||||
def test_handle_disable_channel_help(self):
|
||||
"""Test disable-channel help message"""
|
||||
self.assert_help(
|
||||
handle_disable_channel,
|
||||
"""Usage: %s disable-channel [options] <channelname> [<channelname> ...]
|
||||
(Specify the --help global option for a list of other help options)
|
||||
|
||||
Options:
|
||||
-h, --help show this help message and exit
|
||||
--comment=COMMENT Comment indicating why the channel(s) are being disabled
|
||||
""" % self.progname)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
@ -34,6 +34,7 @@ Options:
|
|||
--name=NAME New channel name
|
||||
--description=DESCRIPTION
|
||||
Description of channel
|
||||
--comment=COMMENT Comment of channel
|
||||
""" % self.progname)
|
||||
|
||||
@mock.patch('sys.stderr', new_callable=six.StringIO)
|
||||
|
|
|
|||
115
tests/test_cli/test_enable_channel.py
Normal file
115
tests/test_cli/test_enable_channel.py
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
import unittest
|
||||
|
||||
import mock
|
||||
import six
|
||||
|
||||
import koji
|
||||
from koji_cli.commands import handle_enable_channel
|
||||
from . import utils
|
||||
|
||||
|
||||
class TestEnableChannel(utils.CliTestCase):
|
||||
# Show long diffs in error output...
|
||||
maxDiff = None
|
||||
|
||||
def setUp(self):
|
||||
self.error_format = """Usage: %s enable-channel [options] <channelname> [<channelname> ...]
|
||||
(Specify the --help global option for a list of other help options)
|
||||
|
||||
%s: error: {message}
|
||||
""" % (self.progname, self.progname)
|
||||
self.channelinfo = [
|
||||
{'comment': None, 'description': None, 'enabled': False, 'id': 1,
|
||||
'name': 'test-channel'}
|
||||
]
|
||||
|
||||
def __vm(self, result):
|
||||
m = koji.VirtualCall('mcall_method', [], {})
|
||||
if isinstance(result, dict) and result.get('faultCode'):
|
||||
m._result = result
|
||||
else:
|
||||
m._result = (result,)
|
||||
return m
|
||||
|
||||
@mock.patch('sys.stderr', new_callable=six.StringIO)
|
||||
@mock.patch('sys.stdout', new_callable=six.StringIO)
|
||||
@mock.patch('koji_cli.commands.activate_session')
|
||||
def test_handle_enable_channel(self, activate_session_mock, stdout, stderr):
|
||||
"""Test enable-channel function"""
|
||||
options = mock.MagicMock()
|
||||
session = mock.MagicMock()
|
||||
|
||||
mcall = session.multicall.return_value.__enter__.return_value
|
||||
|
||||
mcall.getChannel.return_value = self.__vm(None)
|
||||
|
||||
arguments = ['channel1', 'channel2']
|
||||
with self.assertRaises(SystemExit) as ex:
|
||||
handle_enable_channel(options, session, arguments)
|
||||
self.assertExitCode(ex, 1)
|
||||
activate_session_mock.assert_called_once()
|
||||
session.multicall.assert_called_once()
|
||||
session.enableChannel.assert_not_called()
|
||||
expect = ''
|
||||
for host in arguments:
|
||||
expect += "No such channel: %s\n" % host
|
||||
stderr_exp = "No changes made. Please correct the command line.\n"
|
||||
self.assert_console_message(stdout, expect)
|
||||
self.assert_console_message(stderr, stderr_exp)
|
||||
|
||||
# reset session mocks
|
||||
activate_session_mock.reset_mock()
|
||||
session.multicall.reset_mock()
|
||||
session.enableChannel.reset_mock()
|
||||
mcall = session.multicall.return_value.__enter__.return_value
|
||||
|
||||
mcall.getChannel.return_value = self.__vm(self.channelinfo)
|
||||
|
||||
arguments = ['channel1', 'channel2', '--comment', 'enable channel test']
|
||||
handle_enable_channel(options, session, arguments)
|
||||
activate_session_mock.assert_called_once()
|
||||
self.assertEqual(2, session.multicall.call_count)
|
||||
self.assert_console_message(stdout, '')
|
||||
|
||||
@mock.patch('sys.stdout', new_callable=six.StringIO)
|
||||
@mock.patch('koji_cli.commands.activate_session')
|
||||
def test_handle_enable_host_no_argument(self, activate_session_mock, stdout):
|
||||
"""Test enable-channel function without arguments"""
|
||||
options = mock.MagicMock()
|
||||
session = mock.MagicMock()
|
||||
|
||||
session.getChannel.return_value = None
|
||||
session.multicall.return_value = [[None]]
|
||||
session.enableChannel.return_value = True
|
||||
|
||||
expected = self.format_error_message("At least one channel must be specified")
|
||||
self.assert_system_exit(
|
||||
handle_enable_channel,
|
||||
options,
|
||||
session,
|
||||
[],
|
||||
stderr=expected,
|
||||
activate_session=None)
|
||||
|
||||
activate_session_mock.assert_not_called()
|
||||
session.getChannel.assert_not_called()
|
||||
session.multicall.assert_not_called()
|
||||
session.enableChannel.assert_not_called()
|
||||
|
||||
def test_handle_enable_channel_help(self):
|
||||
"""Test enable-channel help message"""
|
||||
self.assert_help(
|
||||
handle_enable_channel,
|
||||
"""Usage: %s enable-channel [options] <channelname> [<channelname> ...]
|
||||
(Specify the --help global option for a list of other help options)
|
||||
|
||||
Options:
|
||||
-h, --help show this help message and exit
|
||||
--comment=COMMENT Comment indicating why the channel(s) are being enabled
|
||||
""" % self.progname)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
@ -1,28 +1,30 @@
|
|||
from __future__ import absolute_import
|
||||
import mock
|
||||
|
||||
import unittest
|
||||
|
||||
import mock
|
||||
from six.moves import StringIO
|
||||
|
||||
import koji
|
||||
|
||||
from koji_cli.commands import anon_handle_list_channels
|
||||
from . import utils
|
||||
|
||||
|
||||
class TestListChannels(utils.CliTestCase):
|
||||
maxDiff = None
|
||||
|
||||
class TestListChannels(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.options = mock.MagicMock()
|
||||
self.options.quiet = True
|
||||
self.session = mock.MagicMock()
|
||||
self.session.getAPIVersion.return_value = koji.API_VERSION
|
||||
self.args = []
|
||||
|
||||
@mock.patch('sys.stdout', new_callable=StringIO)
|
||||
@mock.patch('koji_cli.commands.ensure_connection')
|
||||
def test_list_channels(self, ensure_connection_mock, stdout):
|
||||
self.session.listChannels.return_value = [
|
||||
{'id': 1, 'name': 'default'},
|
||||
{'id': 2, 'name': 'test'},
|
||||
self.list_channels = [
|
||||
{'id': 1, 'name': 'default', 'enabled': True, 'comment': 'test-comment-1',
|
||||
'description': 'test-description-1'},
|
||||
{'id': 2, 'name': 'test', 'enabled': False, 'comment': 'test-comment-2',
|
||||
'description': 'test-description-2'},
|
||||
]
|
||||
self.session.multiCall.return_value = [
|
||||
self.list_hosts_mc = [
|
||||
[[
|
||||
{'enabled': True, 'ready': True, 'capacity': 2.0, 'task_load': 1.34},
|
||||
{'enabled': True, 'ready': False, 'capacity': 2.0, 'task_load': 0.0},
|
||||
|
|
@ -32,16 +34,78 @@ class TestListChannels(unittest.TestCase):
|
|||
{'enabled': True, 'ready': True, 'capacity': 2.0, 'task_load': 1.34},
|
||||
{'enabled': False, 'ready': True, 'capacity': 2.0, 'task_load': 0.34},
|
||||
{'enabled': True, 'ready': False, 'capacity': 2.0, 'task_load': 0.0},
|
||||
]],
|
||||
]]
|
||||
]
|
||||
|
||||
anon_handle_list_channels(self.options, self.session, self.args)
|
||||
@mock.patch('sys.stdout', new_callable=StringIO)
|
||||
@mock.patch('koji_cli.commands.ensure_connection')
|
||||
def test_list_channels(self, ensure_connection_mock, stdout):
|
||||
self.session.listChannels.return_value = self.list_channels
|
||||
self.session.multiCall.return_value = self.list_hosts_mc
|
||||
args = []
|
||||
|
||||
anon_handle_list_channels(self.options, self.session, args)
|
||||
|
||||
actual = stdout.getvalue()
|
||||
print(actual)
|
||||
expected = """\
|
||||
default 3 1 0 1 6 22%
|
||||
test 2 2 1 1 6 28%
|
||||
test [disabled] 2 2 1 1 6 28%
|
||||
"""
|
||||
self.assertMultiLineEqual(actual, expected)
|
||||
ensure_connection_mock.assert_called_once_with(self.session, self.options)
|
||||
|
||||
@mock.patch('sys.stdout', new_callable=StringIO)
|
||||
@mock.patch('koji_cli.commands.ensure_connection')
|
||||
def test_list_channels_with_comment(self, ensure_connection_mock, stdout):
|
||||
self.session.listChannels.return_value = self.list_channels
|
||||
self.session.multiCall.return_value = self.list_hosts_mc
|
||||
args = ['--comment']
|
||||
anon_handle_list_channels(self.options, self.session, args)
|
||||
|
||||
actual = stdout.getvalue()
|
||||
print(actual)
|
||||
expected = 'default 3 1 0 1 6 22% ' \
|
||||
'test-comment-1 \n' \
|
||||
'test [disabled] 2 2 1 1 6 28% ' \
|
||||
'test-comment-2 \n'
|
||||
self.assertMultiLineEqual(actual, expected)
|
||||
ensure_connection_mock.assert_called_once_with(self.session, self.options)
|
||||
|
||||
@mock.patch('sys.stdout', new_callable=StringIO)
|
||||
@mock.patch('koji_cli.commands.ensure_connection')
|
||||
def test_list_channels_with_description(self, ensure_connection_mock, stdout):
|
||||
self.session.listChannels.return_value = self.list_channels
|
||||
self.session.multiCall.return_value = self.list_hosts_mc
|
||||
args = ['--description']
|
||||
anon_handle_list_channels(self.options, self.session, args)
|
||||
|
||||
actual = stdout.getvalue()
|
||||
print(actual)
|
||||
expected = 'default 3 1 0 1 6 22% ' \
|
||||
'test-description-1 \n' \
|
||||
'test [disabled] 2 2 1 1 6 28% ' \
|
||||
'test-description-2 \n'
|
||||
self.assertMultiLineEqual(actual, expected)
|
||||
ensure_connection_mock.assert_called_once_with(self.session, self.options)
|
||||
|
||||
def test_list_channels_help(self):
|
||||
self.assert_help(
|
||||
anon_handle_list_channels,
|
||||
"""Usage: %s list-channels [options]
|
||||
(Specify the --help global option for a list of other help options)
|
||||
|
||||
Options:
|
||||
-h, --help show this help message and exit
|
||||
--simple Print just list of channels without additional info
|
||||
--quiet Do not print header information
|
||||
--comment Show comments
|
||||
--description Show descriptions
|
||||
--enabled Limit to enabled channels
|
||||
--not-enabled Limit to not enabled channels
|
||||
--disabled Alias for --not-enabled
|
||||
""" % self.progname)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
|||
|
|
@ -34,8 +34,8 @@ class TestListHosts(utils.CliTestCase):
|
|||
@mock.patch('koji_cli.commands.ensure_connection')
|
||||
def test_list_hosts_valid(self, ensure_connection, stdout):
|
||||
host_update = 1615875554.862938
|
||||
expected = """kojibuilder Y Y 0.0/2.0 x86_64 Tue, 16 Mar 2021 06:19:14 UTC
|
||||
"""
|
||||
expected = "kojibuilder Y Y 0.0/2.0 x86_64 " \
|
||||
"Tue, 16 Mar 2021 06:19:14 UTC \n"
|
||||
list_hosts = [{'arches': 'x86_64',
|
||||
'capacity': 2.0,
|
||||
'comment': None,
|
||||
|
|
|
|||
|
|
@ -31,19 +31,22 @@ class TestAddHostToChannel(unittest.TestCase):
|
|||
def tearDown(self):
|
||||
mock.patch.stopall()
|
||||
|
||||
@mock.patch('kojihub.get_channel')
|
||||
@mock.patch('kojihub.list_channels')
|
||||
@mock.patch('kojihub.get_channel_id')
|
||||
@mock.patch('kojihub.get_host')
|
||||
def test_valid(self, get_host, get_channel_id, list_channels):
|
||||
def test_valid(self, get_host, get_channel_id, list_channels, get_channel):
|
||||
name = 'hostname'
|
||||
cname = 'channel_name'
|
||||
get_host.return_value = {'id': 123, 'name': name}
|
||||
get_channel_id.return_value = 456
|
||||
list_channels.return_value = [{'id': 1, 'name': 'default'}]
|
||||
get_channel.return_value = {'enabled': True}
|
||||
|
||||
kojihub.add_host_to_channel(name, cname, create=False)
|
||||
|
||||
get_host.assert_called_once_with(name)
|
||||
get_channel.assert_called_once_with(456)
|
||||
get_channel_id.assert_called_once_with(cname, create=False)
|
||||
list_channels.assert_called_once_with(123)
|
||||
|
||||
|
|
@ -88,19 +91,22 @@ class TestAddHostToChannel(unittest.TestCase):
|
|||
get_channel_id.assert_called_once_with(cname, create=False)
|
||||
self.assertEqual(len(self.inserts), 0)
|
||||
|
||||
@mock.patch('kojihub.get_channel')
|
||||
@mock.patch('kojihub.list_channels')
|
||||
@mock.patch('kojihub.get_channel_id')
|
||||
@mock.patch('kojihub.get_host')
|
||||
def test_no_channel_create(self, get_host, get_channel_id, list_channels):
|
||||
def test_no_channel_create(self, get_host, get_channel_id, list_channels, get_channel):
|
||||
name = 'hostname'
|
||||
cname = 'channel_name'
|
||||
get_host.return_value = {'id': 123, 'name': name}
|
||||
get_channel_id.return_value = 456
|
||||
list_channels.return_value = [{'id': 1, 'name': 'default'}]
|
||||
get_channel.return_value = {'enabled': True}
|
||||
|
||||
kojihub.add_host_to_channel(name, cname, create=True)
|
||||
|
||||
get_host.assert_called_once_with(name)
|
||||
get_channel.assert_called_once_with(456)
|
||||
get_channel_id.assert_called_once_with(cname, create=True)
|
||||
list_channels.assert_called_once_with(123)
|
||||
|
||||
|
|
@ -116,20 +122,23 @@ class TestAddHostToChannel(unittest.TestCase):
|
|||
self.assertEqual(insert.data, data)
|
||||
self.assertEqual(insert.rawdata, {})
|
||||
|
||||
@mock.patch('kojihub.get_channel')
|
||||
@mock.patch('kojihub.list_channels')
|
||||
@mock.patch('kojihub.get_channel_id')
|
||||
@mock.patch('kojihub.get_host')
|
||||
def test_exists(self, get_host, get_channel_id, list_channels):
|
||||
def test_exists(self, get_host, get_channel_id, list_channels, get_channel):
|
||||
name = 'hostname'
|
||||
cname = 'channel_name'
|
||||
get_host.return_value = {'id': 123, 'name': name}
|
||||
get_channel_id.return_value = 456
|
||||
list_channels.return_value = [{'id': 456, 'name': cname}]
|
||||
get_channel.return_value = {'enabled': True}
|
||||
|
||||
with self.assertRaises(koji.GenericError):
|
||||
kojihub.add_host_to_channel(name, cname, create=False)
|
||||
|
||||
get_host.assert_called_once_with(name)
|
||||
get_channel.assert_called_once_with(456)
|
||||
get_channel_id.assert_called_once_with(cname, create=False)
|
||||
list_channels.assert_called_once_with(123)
|
||||
self.assertEqual(len(self.inserts), 0)
|
||||
|
|
|
|||
43
tests/test_hub/test_disable_channel.py
Normal file
43
tests/test_hub/test_disable_channel.py
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
import unittest
|
||||
|
||||
import mock
|
||||
|
||||
import koji
|
||||
import kojihub
|
||||
|
||||
UP = kojihub.UpdateProcessor
|
||||
|
||||
|
||||
class TestDisableChannel(unittest.TestCase):
|
||||
|
||||
def getUpdate(self, *args, **kwargs):
|
||||
update = UP(*args, **kwargs)
|
||||
update.execute = mock.MagicMock()
|
||||
self.updates.append(update)
|
||||
return update
|
||||
|
||||
def setUp(self):
|
||||
self.exports = kojihub.RootExports()
|
||||
self.get_channel = mock.patch('kojihub.get_channel').start()
|
||||
self.UpdateProcessor = mock.patch('kojihub.UpdateProcessor',
|
||||
side_effect=self.getUpdate).start()
|
||||
self.updates = []
|
||||
self.channelname = 'test-channel'
|
||||
|
||||
def test_non_exist_channel(self):
|
||||
self.get_channel.return_value = None
|
||||
with self.assertRaises(koji.GenericError) as cm:
|
||||
self.exports.disableChannel(self.channelname)
|
||||
self.assertEqual("No such channel: %s" % self.channelname, str(cm.exception))
|
||||
|
||||
def test_valid(self):
|
||||
self.get_channel.return_value = {'comment': None, 'description': None,
|
||||
'enabled': True, 'id': 1, 'name': 'test-channel'}
|
||||
self.exports.disableChannel(self.channelname, comment='test-comment')
|
||||
self.assertEqual(len(self.updates), 1)
|
||||
update = self.updates[0]
|
||||
self.assertEqual(update.table, 'channels')
|
||||
self.assertEqual(update.data, {'comment': 'test-comment', 'enabled': False})
|
||||
self.assertEqual(update.values, {'comment': None, 'description': None, 'enabled': True,
|
||||
'id': 1, 'name': 'test-channel'})
|
||||
self.assertEqual(update.clauses, ['id = %(id)i'])
|
||||
|
|
@ -84,7 +84,7 @@ class TestEditChannel(unittest.TestCase):
|
|||
|
||||
r = self.exports.editChannel(self.channel_name, name=self.channel_name_new,
|
||||
description='description_new')
|
||||
self.assertIsNone(r)
|
||||
self.assertTrue(r)
|
||||
expected_calls = [mock.call(self.channel_name, strict=True),
|
||||
mock.call(self.channel_name_new, strict=False)]
|
||||
get_channel.assert_has_calls(expected_calls)
|
||||
|
|
|
|||
44
tests/test_hub/test_enable_channel.py
Normal file
44
tests/test_hub/test_enable_channel.py
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
import unittest
|
||||
|
||||
import mock
|
||||
|
||||
import koji
|
||||
import kojihub
|
||||
|
||||
UP = kojihub.UpdateProcessor
|
||||
|
||||
|
||||
class TestEnableChannel(unittest.TestCase):
|
||||
|
||||
def getUpdate(self, *args, **kwargs):
|
||||
update = UP(*args, **kwargs)
|
||||
update.execute = mock.MagicMock()
|
||||
self.updates.append(update)
|
||||
return update
|
||||
|
||||
def setUp(self):
|
||||
self.exports = kojihub.RootExports()
|
||||
self.get_channel = mock.patch('kojihub.get_channel').start()
|
||||
self.UpdateProcessor = mock.patch('kojihub.UpdateProcessor',
|
||||
side_effect=self.getUpdate).start()
|
||||
self.updates = []
|
||||
self.channelname = 'test-channel'
|
||||
|
||||
def test_non_exist_channel(self):
|
||||
|
||||
self.get_channel.return_value = None
|
||||
with self.assertRaises(koji.GenericError) as cm:
|
||||
self.exports.enableChannel(self.channelname)
|
||||
self.assertEqual("No such channel: %s" % self.channelname, str(cm.exception))
|
||||
|
||||
def test_valid(self):
|
||||
self.get_channel.return_value = {'comment': None, 'description': None,
|
||||
'enabled': False, 'id': 1, 'name': 'test-channel'}
|
||||
self.exports.enableChannel(self.channelname, comment='test-comment')
|
||||
self.assertEqual(len(self.updates), 1)
|
||||
update = self.updates[0]
|
||||
self.assertEqual(update.table, 'channels')
|
||||
self.assertEqual(update.data, {'comment': 'test-comment', 'enabled': True})
|
||||
self.assertEqual(update.values, {'comment': None, 'description': None, 'enabled': False,
|
||||
'id': 1, 'name': 'test-channel'})
|
||||
self.assertEqual(update.clauses, ['id = %(id)i'])
|
||||
|
|
@ -33,10 +33,12 @@ class TestListChannels(unittest.TestCase):
|
|||
self.assertEqual(len(self.queries), 1)
|
||||
query = self.queries[0]
|
||||
self.assertEqual(query.tables, ['channels'])
|
||||
self.assertEqual(query.aliases, ['description', 'id', 'name'])
|
||||
self.assertEqual(query.aliases, ['comment', 'description', 'enabled', 'id',
|
||||
'name'])
|
||||
self.assertEqual(query.joins, None)
|
||||
self.assertEqual(query.values, {})
|
||||
self.assertEqual(query.columns, ['channels.description', 'channels.id', 'channels.name'])
|
||||
self.assertEqual(query.columns, ['channels.comment', 'channels.description',
|
||||
'channels.enabled', 'channels.id', 'channels.name'])
|
||||
self.assertEqual(query.clauses, None)
|
||||
|
||||
def test_host(self):
|
||||
|
|
@ -50,10 +52,12 @@ class TestListChannels(unittest.TestCase):
|
|||
'host_channels.host_id = %(host_id)s'
|
||||
]
|
||||
self.assertEqual(query.tables, ['host_channels'])
|
||||
self.assertEqual(query.aliases, ['description', 'id', 'name'])
|
||||
self.assertEqual(query.aliases, ['comment', 'description', 'enabled', 'id',
|
||||
'name'])
|
||||
self.assertEqual(query.joins, joins)
|
||||
self.assertEqual(query.values, {'host_id': 1234})
|
||||
self.assertEqual(query.columns, ['channels.description', 'channels.id', 'channels.name'])
|
||||
self.assertEqual(query.columns, ['channels.comment', 'channels.description',
|
||||
'channels.enabled', 'channels.id', 'channels.name'])
|
||||
self.assertEqual(query.clauses, clauses)
|
||||
|
||||
def test_host_and_event(self):
|
||||
|
|
@ -68,10 +72,12 @@ class TestListChannels(unittest.TestCase):
|
|||
'host_channels.host_id = %(host_id)s',
|
||||
]
|
||||
self.assertEqual(query.tables, ['host_channels'])
|
||||
self.assertEqual(query.aliases, ['description', 'id', 'name'])
|
||||
self.assertEqual(query.aliases, ['comment', 'description', 'enabled', 'id',
|
||||
'name'])
|
||||
self.assertEqual(query.joins, joins)
|
||||
self.assertEqual(query.values, {'host_id': 1234})
|
||||
self.assertEqual(query.columns, ['channels.description', 'channels.id', 'channels.name'])
|
||||
self.assertEqual(query.columns, ['channels.comment', 'channels.description',
|
||||
'channels.enabled', 'channels.id', 'channels.name'])
|
||||
self.assertEqual(query.clauses, clauses)
|
||||
|
||||
def test_event_only(self):
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Name</th><td>$channel.name</td>
|
||||
<th>Name</th><td>$util.escapeHTML($channel.name)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>ID</th><td>$channel.id</td>
|
||||
|
|
@ -14,6 +14,16 @@
|
|||
<tr>
|
||||
<th>Description</th><td>$util.escapeHTML($channel.description)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
#set $enabled = $channel.enabled and 'yes' or 'no'
|
||||
<th>Enabled?</th>
|
||||
<td class="$enabled">
|
||||
$util.imageTag($enabled)
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Comment</th><td>$util.escapeHTML($channel.comment)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Active Tasks</th><td><a href="tasks?view=flat&channelID=$channel.id">$taskCount</a></td>
|
||||
</tr>
|
||||
|
|
|
|||
|
|
@ -60,6 +60,9 @@
|
|||
<tr>
|
||||
<th>
|
||||
<a href="channelinfo?channelID=$channel['id']">$channel['name']</a>
|
||||
#if not $channel['enabled_channel']
|
||||
[disabled]
|
||||
#end if
|
||||
</th>
|
||||
<td width="$graphWidth" class="graph">
|
||||
#if $channel['capacityPerc']
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@
|
|||
<th>Channels</th>
|
||||
<td>
|
||||
#for $channel in $channels
|
||||
<a href="channelinfo?channelID=$channel.id">$channel.name</a><br/>
|
||||
<a href="channelinfo?channelID=$channel.id" class="$channel.enabled">$channel.name</a><br/>
|
||||
#end for
|
||||
#if not $channels
|
||||
No channels
|
||||
|
|
|
|||
|
|
@ -123,8 +123,8 @@ in $channel channel
|
|||
<td><a href="hostinfo?hostID=$host.id">$host.name</a></td>
|
||||
<td>$host.arches</td>
|
||||
<td>
|
||||
#for $channame, $chan_id in zip($host.channels, $host.channels_id)
|
||||
<a href="channelinfo?channelID=$chan_id">$channame</a>
|
||||
#for $channame, $chan_id, $chan_enabled in zip($host.channels, $host.channels_id, $host.channels_enabled)
|
||||
<a href="channelinfo?channelID=$chan_id" class="$chan_enabled">$channame</a>
|
||||
#end for
|
||||
</td>
|
||||
<td class="$str($bool($host.enabled)).lower()">#if $host.enabled then $util.imageTag('yes') else $util.imageTag('no')#</td>
|
||||
|
|
|
|||
|
|
@ -1661,9 +1661,14 @@ def hosts(environ, state='enabled', start=None, order='name', ready='all', chann
|
|||
for host, channels in zip(hosts, list_channels):
|
||||
host['channels'] = []
|
||||
host['channels_id'] = []
|
||||
host['channels_enabled'] = []
|
||||
for chan in channels.result:
|
||||
host['channels'].append(chan['name'])
|
||||
host['channels_id'].append(chan['id'])
|
||||
if chan['enabled']:
|
||||
host['channels_enabled'].append('enabled')
|
||||
else:
|
||||
host['channels_enabled'].append('disabled')
|
||||
|
||||
if channel != 'all':
|
||||
hosts = [x for x in hosts if channel in x['channels']]
|
||||
|
|
@ -1709,6 +1714,11 @@ def hostinfo(environ, hostID=None, userID=None):
|
|||
|
||||
channels = server.listChannels(host['id'])
|
||||
channels.sort(key=_sortbyname)
|
||||
for chan in channels:
|
||||
if chan['enabled']:
|
||||
chan['enabled'] = 'enabled'
|
||||
else:
|
||||
chan['enabled'] = 'disabled'
|
||||
buildroots = server.listBuildroots(hostID=host['id'],
|
||||
state=[state[1] for state in koji.BR_STATES.items()
|
||||
if state[0] != 'EXPIRED'])
|
||||
|
|
@ -2359,6 +2369,7 @@ def clusterhealth(environ, arch='__all__'):
|
|||
for host in hosts:
|
||||
arches |= set(host['arches'].split())
|
||||
hosts = _filter_hosts_by_arch(hosts, arch)
|
||||
channel['enabled_channel'] = channel['enabled']
|
||||
channel['enabled'] = len([x for x in hosts if x['enabled']])
|
||||
channel['disabled'] = len(hosts) - channel['enabled']
|
||||
channel['ready'] = len([x for x in hosts if x['ready']])
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue