Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

scan/gscan: consistent default behaviour #2666

Merged
merged 2 commits into from May 16, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGES.md
Expand Up @@ -71,6 +71,13 @@ from multi-line `script` items in task definitions, for cleaner job scripts.

### Fixes

[#2666](https://github.com/cylc/cylc/pull/2666) - `cylc scan`: fix default
behavior to only obtain suite information from the `~/cylc-run/` of the current
user. This is consistent with `cylc gscan`. However, the `--name=PATTERN`
(`-n PATTERN`) option has also been modified to be consistent with
`cylc gscan`, so `cylc scan --name=bar` will only match the suite `bar` but not
the suites `foobar` and `barbaz`.

[#2593](https://github.com/cylc/cylc/pull/2593) - fix polling after job
execution timeout (configured pre-poll delays were being ignored).

Expand Down
30 changes: 10 additions & 20 deletions bin/cylc-scan
Expand Up @@ -50,8 +50,8 @@ import re
import json

from cylc.cfgspec.glbl_cfg import glbl_cfg
from cylc.hostuserutil import get_user
from cylc.network.port_scan import scan_many, get_scan_items_from_fs
from cylc.network.port_scan import (
get_scan_items_from_fs, re_compile_filters, scan_many)
from cylc.option_parsers import CylcOptionParser as COP
from cylc.suite_status import (
KEY_DESCRIPTION, KEY_META, KEY_NAME, KEY_OWNER, KEY_STATES,
Expand Down Expand Up @@ -200,28 +200,18 @@ def main():
else:
# Any suite name.
patterns_name = ['.*']
patterns_owner = None
if options.patterns_owner:
patterns_owner = options.patterns_owner
else:
# Just the user's suites.
patterns_owner = [get_user()]
# Compile and check "name" and "owner" regular expressions
cres = {}
for key, patterns in [
('name', patterns_name), ('suite-owner', patterns_owner)]:
try:
cres[key] = re.compile(r'(' + r')|('.join(patterns) + r')')
except re.error:
for pattern in patterns:
try:
re.compile(pattern)
except re.error:
parser.error(
'--%s=%s: bad regular expression' % (key, pattern))
try:
cre_owner, cre_name = re_compile_filters(patterns_owner, patterns_name)
except ValueError as exc:
parser.error(str(exc))
if options.all_ports:
args.extend(glbl_cfg().get(["suite host scanning", "hosts"]))
if not args:
args = get_scan_items_from_fs(cres['suite-owner'])
args = get_scan_items_from_fs(cre_owner)
if not args:
return

Expand All @@ -231,9 +221,9 @@ def main():
name = suite_identity[KEY_NAME]
owner = suite_identity[KEY_OWNER]

if not cres['name'].match(name):
if cre_name and not cre_name.match(name):
continue
if not cres['suite-owner'].match(owner):
if cre_owner and not cre_owner.match(owner):
continue
if options.json_format:
json_filter.append([host, port, suite_identity])
Expand Down
2 changes: 1 addition & 1 deletion lib/cylc/daemonize.py
Expand Up @@ -30,7 +30,7 @@
$ cylc get-suite-contact %(suite)s

Other ways to see if the suite is still running:
$ cylc scan -n '\b%(suite)s\b' %(host)s
$ cylc scan -n '%(suite)s' %(host)s
$ cylc ping -v --host=%(host)s %(suite)s
$ ps %(ps_opts)s %(pid)s # on %(host)s

Expand Down
19 changes: 5 additions & 14 deletions lib/cylc/gui/gscan.py
Expand Up @@ -35,6 +35,7 @@
KEY_PORT, get_scan_menu, launch_gcylc, update_suites_info,
launch_hosts_dialog, launch_about_dialog)
from cylc.gui.util import get_icon, setup_icons, set_exception_hook_dialog
from cylc.network.port_scan import re_compile_filters
from cylc.suite_status import (
KEY_GROUP, KEY_META, KEY_STATES, KEY_TASKS_BY_STATE, KEY_TITLE,
KEY_UPDATE_TIME)
Expand Down Expand Up @@ -169,21 +170,11 @@ def __init__(
self.treeview.connect("button-press-event",
self._on_button_press_event)

patterns = {"name": None, "owner": None}
for label, items in [
("owner", patterns_owner), ("name", patterns_name)]:
if items:
patterns[label] = r"\A(?:" + r")|(?:".join(items) + r")\Z"
try:
patterns[label] = re.compile(patterns[label])
except re.error:
raise ValueError("Invalid %s pattern: %s" % (label, items))
cre_owner, cre_name = re_compile_filters(patterns_owner, patterns_name)

self.updater = ScanAppUpdater(
self.window, hosts, suite_treemodel, self.treeview,
comms_timeout=comms_timeout, interval=interval,
group_column_id=self.GROUP_COLUMN,
name_pattern=patterns["name"], owner_pattern=patterns["owner"])
comms_timeout, interval, self.GROUP_COLUMN, cre_owner, cre_name)

self.updater.start()

Expand Down Expand Up @@ -759,7 +750,7 @@ class ScanAppUpdater(threading.Thread):

def __init__(self, window, hosts, suite_treemodel, suite_treeview,
comms_timeout=None, interval=None, group_column_id=0,
name_pattern=None, owner_pattern=None):
owner_pattern=None, name_pattern=None):
self.window = window
if hosts:
self.hosts = hosts
Expand All @@ -779,8 +770,8 @@ def __init__(self, window, hosts, suite_treemodel, suite_treeview,
self.group_column_id = group_column_id
self.tasks_by_state = {}
self.warning_times = {}
self.name_pattern = name_pattern
self.owner_pattern = owner_pattern
self.name_pattern = name_pattern
super(ScanAppUpdater, self).__init__()

@staticmethod
Expand Down
23 changes: 23 additions & 0 deletions lib/cylc/network/port_scan.py
Expand Up @@ -20,6 +20,7 @@
from multiprocessing import cpu_count, Process, Pipe
import os
from pwd import getpwall
import re
import sys
from time import sleep, time
import traceback
Expand Down Expand Up @@ -232,6 +233,28 @@ def scan_many(items, timeout=None, updater=None):
return results


def re_compile_filters(patterns_owner=None, patterns_name=None):
"""Compile regexp for suite owner and suite name scan filters.

Arguments:
patterns_owner (list): List of suite owner patterns
patterns_name (list): List of suite name patterns

Returns (tuple):
A 2-element tuple in the form (cre_owner, cre_name). Either or both
element can be None to allow for the default scan behaviour.
"""
cres = {'owner': None, 'name': None}
for label, items in [('owner', patterns_owner), ('name', patterns_name)]:
if items:
cres[label] = r'\A(?:' + r')|(?:'.join(items) + r')\Z'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is probably the right way to go but It's worth noting this is a change in behaviour, partial patterns used to match.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added an entry to CHANGES.md and modified the cylc scan syntax on cylc run daemonize.

try:
cres[label] = re.compile(cres[label])
except re.error:
raise ValueError(r'%s=%s: bad regexp' % (label, items))
return (cres['owner'], cres['name'])


def get_scan_items_from_fs(owner_pattern=None, updater=None):
"""Get list of host:port available to scan using the file system.

Expand Down