import click
from lftools.cli.deploy import deploy
+from lftools.cli.jenkins import jenkins_cli
from lftools.cli.nexus import nexus
from lftools.cli.version import version
from lftools.openstack.cmd import openstack
cli.add_command(deploy)
cli.add_command(openstack)
cli.add_command(nexus)
+cli.add_command(jenkins_cli, name='jenkins')
cli.add_command(version)
--- /dev/null
+# @License EPL-1.0 <http://spdx.org/licenses/EPL-1.0>
+##############################################################################
+# Copyright (c) 2017 The Linux Foundation and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+##############################################################################
+"""Jenkins information."""
+
+__author__ = 'Trevor Bramwell'
+
+
+import click
+import jenkins as jenkins_python # Don't confuse this with the function ...
+from lftools.cli.jenkins.builds import builds
+from lftools.cli.jenkins.nodes import nodes
+from lftools.cli.jenkins.plugins import plugins_init
+
+from six.moves.urllib.error import HTTPError
+
+
+@click.group()
+@click.option('-s', '--server', type=str, required=True, envvar='JENKINS_URL')
+@click.option('-u', '--user', type=str, required=True, envvar='JENKINS_USER')
+@click.option('-p', '--password', type=str, required=True,
+ envvar='JENKINS_PASSWORD')
+@click.pass_context
+def jenkins_cli(ctx, server, user, password):
+ """Query information about the Jenkins Server."""
+ # Initial the Jenkins object and pass it to sub-commands
+ ctx.obj['server'] = jenkins_python.Jenkins(
+ server,
+ username=user,
+ password=password)
+
+
+@click.command()
+@click.option("-n/-y", is_flag=True, prompt="Quiet down Jenkins?", required=True)
+@click.pass_context
+def quiet_down(ctx, n):
+ """Put Jenkins into 'Quiet Down' mode."""
+ version = ctx.obj['server'].get_version()
+ # Ask permission first
+ if n:
+ try:
+ ctx.obj['server'].quiet_down()
+ except HTTPError as m:
+ if m.code == 405:
+ print("\n[%s]\nJenkins %s does not support Quiet Down "
+ "without a CSRF Token. (CVE-2017-04-26)\nPlease "
+ "file a bug with 'python-jenkins'" % (m, version))
+ else:
+ raise m
+
+
+jenkins_cli.add_command(plugins_init, name='plugins')
+jenkins_cli.add_command(nodes)
+jenkins_cli.add_command(builds)
+jenkins_cli.add_command(quiet_down, name='quiet-down')
--- /dev/null
+# @License EPL-1.0 <http://spdx.org/licenses/EPL-1.0>
+##############################################################################
+# Copyright (c) 2017 The Linux Foundation and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+##############################################################################
+"""Jenkins build information."""
+
+__author__ = 'Trevor Bramwell'
+
+import click
+
+
+@click.group()
+@click.pass_context
+def builds(ctx):
+ """Information regarding current builds and the queue."""
+ pass
+
+
+@click.command()
+@click.pass_context
+def running(ctx):
+ """Show all the currently running builds."""
+ running_builds = ctx.obj['server'].get_running_builds()
+
+ for build in running_builds:
+ print("- %s on %s" % (build['name'], build['node']))
+
+
+@click.command()
+@click.pass_context
+def queued(ctx):
+ """Show all jobs waiting in the queue and their status."""
+ queue = ctx.obj['server'].get_queue_info()
+
+ queue_length = len(queue)
+ print("Build Queue (%s)" % queue_length)
+ for build in queue:
+ print(" - %s" % (build['task']['name'])),
+ if build['stuck']:
+ print("[Stuck]")
+ if build['blocked']:
+ print("[Blocked]")
+
+
+builds.add_command(running)
+builds.add_command(queued)
--- /dev/null
+# @License EPL-1.0 <http://spdx.org/licenses/EPL-1.0>
+##############################################################################
+# Copyright (c) 2017 The Linux Foundation and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+##############################################################################
+"""Jenkins node information."""
+
+__author__ = 'Trevor Bramwell'
+
+import click
+
+
+def offline_str(status):
+ """Convert the offline node status from a boolean to a string."""
+ if status:
+ return "Offline"
+ return "Online"
+
+
+@click.group()
+@click.pass_context
+def nodes(ctx):
+ """Find information about builders connected to Jenkins Master."""
+ ctx.obj['nodes'] = ctx.obj['server'].get_nodes()
+
+
+@click.command()
+@click.pass_context
+def list_nodes(ctx):
+ """List Jenkins nodes."""
+ node_list = ctx.obj['nodes']
+
+ for node in node_list:
+ print("%s [%s]" % (node['name'], offline_str(node['offline'])))
+
+
+nodes.add_command(list_nodes, name='list')
--- /dev/null
+# @License EPL-1.0 <http://spdx.org/licenses/EPL-1.0>
+##############################################################################
+# Copyright (c) 2017 The Linux Foundation and others.
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+##############################################################################
+"""Jenkins plugin information."""
+
+__author__ = 'Trevor Bramwell'
+
+import click
+
+
+def checkmark(truthy):
+ """Return a UTF-8 Checkmark or Cross depending on the truthiness of the argument."""
+ if truthy:
+ return u'\u2713'
+ return u'\u2717'
+
+
+def print_plugin(plugin, namefield='longName'):
+ """Print the plugin longName and version."""
+ print("%s:%s" % (plugin[namefield], plugin['version']))
+
+
+@click.group()
+@click.pass_context
+def plugins_init(ctx):
+ """Inspect Jenkins plugins on the server."""
+ ctx.obj['plugins'] = ctx.obj['server'].get_plugins()
+
+
+@click.command()
+@click.pass_context
+def list_plugins(ctx):
+ """List installed plugins.
+
+ Defaults to listing all installed plugins and their current versions
+ """
+ plugins = ctx.obj['plugins']
+ for key in plugins.keys():
+ _, plugin_name = key
+ plugin = plugins[plugin_name]
+ print_plugin(plugin)
+
+
+@click.command()
+@click.pass_context
+def pinned(ctx):
+ """List pinned plugins."""
+ plugins = ctx.obj['plugins']
+ for key in plugins.keys():
+ _, plugin_name = key
+ plugin = plugins[plugin_name]
+ if plugin['pinned']:
+ print_plugin(plugin)
+
+
+@click.command()
+@click.pass_context
+def dynamic(ctx):
+ """List dynamically reloadable plugins."""
+ plugins = ctx.obj['plugins']
+ for key in plugins.keys():
+ _, plugin_name = key
+ plugin = plugins[plugin_name]
+ if plugin['supportsDynamicLoad'] == "YES":
+ print_plugin(plugin)
+
+
+@click.command()
+@click.pass_context
+def needs_update(ctx):
+ """List pending plugin updates."""
+ plugins = ctx.obj['plugins']
+ for key in plugins.keys():
+ _, plugin_name = key
+ plugin = plugins[plugin_name]
+ if plugin['hasUpdate']:
+ print_plugin(plugin)
+
+
+@click.command()
+@click.pass_context
+def enabled(ctx):
+ """List enabled plugins."""
+ plugins = ctx.obj['plugins']
+ for key in plugins.keys():
+ _, plugin_name = key
+ plugin = plugins[plugin_name]
+ if plugin['enabled']:
+ print_plugin(plugin)
+
+
+@click.command()
+@click.pass_context
+def disabled(ctx):
+ """List disabled plugins.
+
+ TODO: In the future this should be part of a command alias and pass a flag
+ to 'enabled' so that we don't duplicate code.
+ """
+ plugins = ctx.obj['plugins']
+ for key in plugins.keys():
+ _, plugin_name = key
+ plugin = plugins[plugin_name]
+ if not plugin['enabled']:
+ print_plugin(plugin)
+
+
+@click.command()
+@click.pass_context
+def active(ctx):
+ """List active plugins."""
+ plugins = ctx.obj['plugins']
+ for key in plugins.keys():
+ _, plugin_name = key
+ plugin = plugins[plugin_name]
+ if plugin['active']:
+ print_plugin(plugin)
+
+
+plugins_init.add_command(list_plugins, name='list')
+plugins_init.add_command(pinned)
+plugins_init.add_command(dynamic)
+plugins_init.add_command(needs_update, name='needs-update')
+plugins_init.add_command(active)
+plugins_init.add_command(enabled)
+plugins_init.add_command(disabled)
sphinx>=1.4.9
sphinxcontrib-programoutput
sphinx_bootstrap_theme>=0.4.14
+python-jenkins
# workarounds to prevent upstream from breaking us
babel<2.4.0