2
0
mirror of https://github.com/xcat2/confluent.git synced 2026-09-29 00:31:09 +00:00

Compare commits

...

1306 Commits

Author SHA1 Message Date
Jarrod Johnson a7b11d1e15 Fix closing ipmi session when not mapped
When not mapped, a noisy KeyError was occuring.  Handle
it to avoid cluttering log if the work is not needed.
2019-12-10 14:38:12 -05:00
Jarrod Johnson 3660cf18cc Fix a number of issues
For one, there were still bytes v. str for python3 issues in the
certificate exception and credential handling for smm and generic
credential lookup.

There was a python2-ism in lldp that needed to be made 2/3 agnostic
with ord() of a 'bytes' member, converting to bytearray for
normalized behavior.

The discovery core had an issue with chained smms where a set
was used which cannot take a dict, and so it is converted to a list.

If a temporary password is used but the user did not provide a permanent
password that is viable, make the error more explicit.
2019-12-10 11:54:24 -05:00
Jarrod Johnson 078afaf7d7 Make SLP more tolerant of malformed data
Unrelated devices may present invalid data
to SLP queries.  Have these conditions better tolerated.
2019-12-06 11:24:30 -05:00
Jarrod Johnson 3ab1eb7f01 Add words to nodefirmware man page
ipmi versus redfish produces some different behaviors, document
some examples in the man page.
2019-12-04 10:14:23 -05:00
Jarrod Johnson fbfdc9322b Raise errors during connection
This improves error behavior when login action
encounters an error.
2019-12-04 10:06:18 -05:00
Jarrod Johnson ef68656bde Fix nodestorage handling of error
Error messages were not properly handled if specific nodes had issues.
Properly provide the error messages.

Additionally, clarify a common uselessly vague error.
2019-12-03 10:04:34 -05:00
Jarrod Johnson 0e04b853f6 Fix common usage of noderange alerts
This fixes the usual circumstance of not having keyed input data.
2019-11-21 16:42:03 -05:00
Jarrod Johnson 63256e37b6 Remove some uses of xrange
Not friendly to python 3
2019-11-21 16:03:48 -05:00
Jarrod Johnson a1b81e978b Pull in websocket client dependency
This enables tsmsol plugin
2019-11-20 15:25:11 -05:00
Jarrod Johnson 06c53e9d89 Make the websocket module optional
Have tsmsol gracefully degrade for Wheezy, where
it is not relevant to that platform.
2019-11-20 13:53:16 -05:00
Jarrod Johnson ab0168b2ec Update man page for nodesupport
Correct typo and clarify that plugins may customize
filenames.
2019-11-20 10:48:08 -05:00
Jarrod Johnson 473bb39c54 Fix packaging omission of console plugins 2019-11-20 10:04:38 -05:00
Jarrod Johnson a48ecd8c78 Add hardware and firmware info to CNOS
CNOS devices now have nodefirmware and nodeinventory.
2019-11-15 16:08:28 -05:00
Jarrod Johnson 30398fc434 More explicit follower health checking
Be more careful about collective member health assessment,
explicitly closing a follower when it has failure and prefacing
collective commands with a check prior to performing the actual
changes.
2019-11-11 10:49:25 -05:00
Jarrod Johnson 0ed7e4eac3 Merge branch 'master' of github.com:jjohnson42/confluent 2019-11-07 11:26:04 -05:00
Jarrod Johnson 0d2999c7a8 Properly relay errors on console start
Rather than always saying console.method is not set, relay
the str of the exception to give a more accurate info.
2019-11-07 11:25:49 -05:00
Jarrod Johnson 75010ac6f0 Guard against accidental node duplication
If two nodes have same bmc, block one of them to prevent massive
fluctuation back and forth.
2019-11-07 11:10:26 -05:00
Jarrod Johnson a748cc3032 Remove incorrect check for HOSTUNREACH
This seems incorrect and further redundant with other portions
of the code.  This was causing a 'has no len()' error when encountered.
2019-11-05 13:28:12 -05:00
Jarrod Johnson 28bb143880 Recognize drive in rebuilding state
The rebuilding state was not recognized, add that state.
2019-11-04 14:16:02 -05:00
Jarrod Johnson 4b6899d4af Mark node as 'dirty' if it's group is removed
Group removal would end up with the on-disk copy not reflecting
the node membership, even though in-memory copy is fine.
Fix by adding the missing dirty mark to the entry.
2019-11-04 13:43:29 -05:00
Jarrod Johnson a175fd7345 Allow autosuffix to change passed filename
The resultant file may deviate and thus the chown
must have the updated name.
2019-10-29 16:06:51 -04:00
Jarrod Johnson 12bd473c0d Remove stray debug output 2019-10-29 15:50:48 -04:00
Jarrod Johnson a967c224fe Add TSMSOL plugin
This enables ipmi-free access to TSM SOL console
2019-10-29 15:20:40 -04:00
Jarrod Johnson 72a5f37232 Fix mid-line command completion
Use COMP_CWORD instead of -1 to dynamically decide where to
do completion and what candidates to offer
2019-10-24 15:27:17 -04:00
Jarrod Johnson 5c081a8e2c Remove SYSV init script from RPM packages
All supported RPM distros are systemd now...
2019-10-24 12:16:17 -04:00
Jarrod Johnson c0b69f64b8 Error when noderange tries to use secret
secret. cannot be used in expressions, provide
an error in such a case.
2019-10-24 12:04:47 -04:00
Jarrod Johnson f7fe38f498 Fix problem with reassign and TSM 2019-10-24 10:29:58 -04:00
Jarrod Johnson 5ae949b4eb Add UUID to TSM discovery
The UUID is now available in redfish,
use that to get the UUID.
2019-10-24 10:23:59 -04:00
Jarrod Johnson cec6918c1a Support unsupported bad disks 2019-10-23 17:02:37 -04:00
Jarrod Johnson 3df7a36c48 Fix a number of issues with maxnodes
Some commands did not function correctly
after modifications.
2019-10-23 16:47:42 -04:00
Jarrod Johnson 559e96f7ff Fix location of calling the noderange check 2019-10-23 16:27:18 -04:00
Jarrod Johnson 6f568919e1 Correct instance callout
The wrong value was called out
2019-10-23 15:57:16 -04:00
Jarrod Johnson c441739f68 Try a less jarring exit strategy
Have client not provide a developer looking trace on abort.
2019-10-23 14:41:57 -04:00
Jarrod Johnson a43361bb98 Amend the prompt for single node prompting
Remove the trailing slash
2019-10-23 14:38:45 -04:00
Jarrod Johnson 620263db3e Add maxnodes argument to potentially risky commands
This uses the client maxnodes check to double check.  Useful
for clients that want to sanity check unexpectedly large numbers of
nodes.
2019-10-23 14:20:40 -04:00
Jarrod Johnson dd096104cc Provide mechanism to prompt on large noderanges
Some commands can add options to prompt, and can have that option be
only activated on noderanges over a
certain size.
2019-10-22 15:49:09 -04:00
Jarrod Johnson 191ae762ab Use autosuffix feature of pyghmi
This produces output that is more consistent with support by vendors.
2019-10-22 15:17:31 -04:00
Jarrod Johnson f866b7379c Always relax minimum password interval on auto change
The preconfig could interfere with normal operations.
2019-10-22 10:51:41 -04:00
Jarrod Johnson aab6160d49 Fix compatibility between new and old TSM firmware 2019-10-21 16:20:54 -04:00
Jarrod Johnson e1dffe7c3a Fix compatibility with newer TSM firmware
TSM stopped accepting url encoded, switch to json.  This should work
for older and newer firmware.
2019-10-21 14:39:27 -04:00
Jarrod Johnson 97ca6dc48e Provide more detail on leader when leader is lost 2019-10-21 13:55:43 -04:00
Jarrod Johnson 1d59e1da8c Fix unicode issues in HTML api explorer 2019-10-17 15:36:51 -04:00
Jarrod Johnson 7e6b4fa4d0 Fix HTML view with unicode 2019-10-17 11:25:03 -04:00
Jarrod Johnson 186e89cd87 Fix handling autosense with python3 2019-10-17 09:47:46 -04:00
Jarrod Johnson 73d6511d9e Use python3 explicitly for building source
The source distrobution on CentOS7 does not work well
with python2.  Using python3 to build the dist for python2
and python3 fixes issues with extra data being missed in
packaging.
2019-10-16 13:26:15 -04:00
Jarrod Johnson 065ee48325 Remove non-ascii from man page 2019-10-15 14:00:03 -04:00
Jarrod Johnson 4a35cc25f0 Fix TSM setup with python3 and custom credentials 2019-10-15 11:19:04 -04:00
Jarrod Johnson ceced11ae8 Fix python3 compatibility issue 2019-10-14 16:28:32 -04:00
Jarrod Johnson 62084b3605 More fixes for python3/2 compatibility 2019-10-14 15:22:44 -04:00
Jarrod Johnson a84b88e269 Fix mistake in the expression change 2019-10-14 15:02:45 -04:00
Jarrod Johnson fc626d36ba Fix greenlet 'isAlive'
There is no 'isAlive' in a greenlet.
2019-10-14 13:59:24 -04:00
Jarrod Johnson 606a308046 Fix quorum notification in mixed 2/3 collective 2019-10-14 10:33:13 -04:00
Jarrod Johnson bed0f76dba Fix nodeshell/nodersync python3 changes 2019-10-14 09:37:30 -04:00
Jarrod Johnson 8c4d04a7cd Try utf-8 and fallback to latin1 for 2/3 collective
datetime objects are latin1 encoded from python2.

Not an issue for pure python3 or python2 collectives, but
mitigating problems in the mixed environment
2019-10-11 13:58:30 -04:00
Jarrod Johnson bfbde0f7f3 Fix PXE protocol processing under python3 2019-10-11 13:36:16 -04:00
Jarrod Johnson ba96aea2a6 Fix SR635/SR655 discovery with python3 base 2019-10-11 13:35:46 -04:00
Jarrod Johnson d9f1d6c033 Fix user/password login in python3
The forced bytes of the function was incompatible
with str oriented logic later
2019-10-11 13:21:55 -04:00
Jarrod Johnson 1dac61adca Fix python3 in show user
Showing a user was not working in python3
2019-10-11 13:16:38 -04:00
Jarrod Johnson e008932389 Fix python3 collective leader
rpc needs to be fully binary
2019-10-11 11:11:27 -04:00
Jarrod Johnson b81e5fb3ce Fix python3 issues with noderun and nodeshell 2019-10-11 09:53:01 -04:00
Jarrod Johnson e2a08e7e73 Fix bug in initial recheck scheduling
This was causing rechecktime to not be set correctly.
This caused a trace in python3, but indicates an incorrect
behavior when running under python2
2019-10-11 09:09:42 -04:00
Jarrod Johnson eb48728bc1 Have stringify replace by default
This allows easier handling of invalid decode
data.
2019-10-11 08:57:18 -04:00
Jarrod Johnson c6255fa13b Fix SMM discovery in python3 2019-10-10 17:10:41 -04:00
Jarrod Johnson 2a37d64dc9 Fix XCC discovery in python3
Python3 was picky about the strings, normalize key areas
to strings.
2019-10-10 17:03:57 -04:00
Jarrod Johnson 8101672c3a Fix discovery with python3 2019-10-10 16:49:36 -04:00
Jarrod Johnson 453c344f7f Fix audit log for non root usage with python 3 2019-10-10 16:07:45 -04:00
Jarrod Johnson 9eceda0636 Fix non-root user issue with python3 2019-10-10 16:04:23 -04:00
Jarrod Johnson f28b91499e Fix console replay with formatting
Bold and related items would trigger a problem with python3
2019-10-10 15:01:00 -04:00
Jarrod Johnson 8cab591a8b Add collective member deletion
This allows deletion of a dead member, down to deleting down to non-collective
mode.
2019-10-10 11:30:03 -04:00
Jarrod Johnson 6ce6740b77 Provide deletion of collective member 2019-10-10 08:50:42 -04:00
Jarrod Johnson 8a4a219a14 Fix two more python2 string behavior
In python3, bytes[n] is an int, but not in python2.

Sidestep by doing bytearray() for both, which is consistent
between the two.
2019-10-09 15:06:23 -04:00
Jarrod Johnson a39d45d03c Fix some more python3 issues 2019-10-09 13:42:17 -04:00
Jarrod Johnson bc85d93cf4 More Py3 fixes 2019-10-09 11:20:03 -04:00
Jarrod Johnson 1e963106fe Fix unicode issues with web api 2019-10-09 11:03:30 -04:00
Jarrod Johnson a9f0e345db Another set of python3 fixes 2019-10-08 17:10:56 -04:00
Jarrod Johnson 5353b479d9 More python3 fixes 2019-10-08 13:46:44 -04:00
Jarrod Johnson dbc6747c38 Fix nodebmcreset for python3 2019-10-08 13:43:53 -04:00
Jarrod Johnson 0edd1efe0d Fix python3 dump_keys
When doing format on base64
output, it must be explicitly
coerced into native string
format.
2019-10-08 13:21:34 -04:00
Jarrod Johnson 8e87f5b9e5 Fix python3 issue with base64 and str 2019-10-08 11:20:27 -04:00
Jarrod Johnson 0633b2ca67 Fix syntax error in code 2019-10-08 10:59:44 -04:00
Jarrod Johnson c1953bdad3 Another set of python 3 compatibility
Numerous issues arose, particularly
when participating in a mixed
collective.
2019-10-08 10:45:43 -04:00
Jarrod Johnson 578ba06aa3 Fix python3 problem with octal 2019-10-08 09:06:15 -04:00
Jarrod Johnson 0975881d3b Add monotonic dependency 2019-10-07 17:06:45 -04:00
Jarrod Johnson 8fc3b7c9c0 Implement cross-python collective compat
This enables cross-version compatibility
for a collective.
2019-10-07 15:41:38 -04:00
Jarrod Johnson 6ea6ebd80e Remove superfluous dependency 2019-10-04 16:49:51 -04:00
Jarrod Johnson 744f8899f7 Merge branch 'py3' 2019-10-04 10:57:07 -04:00
Jarrod Johnson 5c288a27dd Have EL8 use python3 for confluent 2019-10-04 10:54:20 -04:00
Jarrod Johnson 74f18d5571 Client side py3 changes 2019-10-04 10:37:48 -04:00
Jarrod Johnson d9be6ae2e9 Close console on disconnect
Fixes leftover console on user initiated disconnect.
2019-10-04 09:57:54 -04:00
Jarrod Johnson 59789bae7d Fix python3 ctypes str usage
In python3, the string is likely to be unicode and incompatible
with the libc function.  If it isn't bytes, force it to be bytes.
2019-10-03 16:06:15 -04:00
Jarrod Johnson 521be5d44d Further Python3 compatibility changes
With this as well as eficompressor and pyghmi updates, things
seem to be in roughly working order
2019-10-03 15:57:56 -04:00
Jarrod Johnson 6fb82bbbad Further Python3 compatibility changes 2019-10-02 11:29:13 -04:00
Jarrod Johnson 90e546bcac Implement a number of py3 compatible adjustments 2019-10-02 08:58:39 -04:00
Jarrod Johnson 147d59cba7 Migrate from PyPAM
PyPAM is no longer part of the distributions.  Closest match is also not in
the distributions and also contains a security problem without an external
patch, so it is pulled in and pull request with copyright and license
intact.
2019-10-01 11:28:43 -04:00
Jarrod Johnson 6a6fd3184e Add missing dependencies for EL8 2019-09-30 10:51:26 -04:00
Jarrod Johnson c532cf9ecf Add EL8 requires adapting to confluent 2019-09-25 15:38:36 -04:00
Jarrod Johnson 8909fb16d6 Change rpm spec to build using python2
This will fix shebang mangling.
2019-09-23 11:11:16 -04:00
Jarrod Johnson 44d6bde3ff Make /usr/bin/env python point to python2
Same as before, more RHEL8 compatibility changes
2019-09-23 11:04:52 -04:00
Jarrod Johnson 56fa13279e Explicitly indicate use of python2
RHEL8 will no longer tolerate implicit use of python.
For now relent to being python2, though ideally one day
it could be either.

Unfortunately, this means once code is ready for python3, we have to
probably implement build time changes for python3 enabled distros
to have different shebangs than python2 distros.
2019-09-23 10:59:00 -04:00
Jarrod Johnson 5008128d57 Add IPv6 support to TSM
TSM firmware fixes enable IPv6, enable our support of it.
2019-09-19 10:02:40 -04:00
Jarrod Johnson ed320f4a17 Add 'check' to permit comparison against current value
For implementing some security policies, it is useful
to check new value against current value.
2019-09-17 09:48:02 -04:00
Jarrod Johnson de8292f6dd Ignore current channel if current channel is disabled
A fluke can cause current channel to be 1 when we are wanting 8.
2019-09-06 13:31:14 -04:00
Jarrod Johnson 8e071a2568 Fix missing import
The smm change omitted a required import.
2019-09-05 12:45:29 -04:00
Jarrod Johnson 7d84d0a021 Add network config to SD635/SD655 discovery
This completes the most critical portion of SD635/SD655 functionality.
2019-09-05 12:10:58 -04:00
Jarrod Johnson c5f75bfa15 Fix slowdown when no password change needed
If the password was pre-provisioned, accelerate the config
phase of tsm bringup.
2019-09-05 11:10:38 -04:00
Jarrod Johnson 99d01d707f Fix incorrect bad auth on freshly changed password
If the database backing the password had changed but cache hadn't updated,
then the cache miss was taken as always meaning no valid login.
2019-09-05 11:09:11 -04:00
Jarrod Johnson 3e1690c860 Add authentication and ipmi configuration to SR635/SR655
Network configuration and the lockout policy remain to be configured.
2019-09-04 16:20:31 -04:00
Jarrod Johnson a3f5630535 Add SR635/SR655 detection
Currently merely detects.  A discover handler will be next step
to populate UUID and do initial setup.
2019-09-03 15:49:27 -04:00
Jarrod Johnson 8d6744947e Extended bmc config support to redfish
Though the underlying library is currenty a stub, bring the
confluent plugin to parity so that nodeconfig works fine
with redfish again.
2019-09-03 11:05:51 -04:00
Jarrod Johnson 21b3c89974 Improve redfish plugin errors and attrib handling
Redfish plugin was not handling the various socket error
behaviors correctly.

Additionally, the attribschanged handler was failing to actually
do anything, so commands would gladly reuse an old redfish
object if it were working.
2019-09-03 10:06:18 -04:00
Jarrod Johnson 9718881c7b Merge branch 'master' of github.com:jjohnson42/confluent 2019-08-30 10:22:59 -04:00
Jarrod Johnson fcbbdc8a8d Add python-pyopenssl and python-dateutil deps
For wheezy, the only supported user wants to
always have collective capability.
Workaround pyghmi missing the dateutil dependency.
2019-08-30 10:22:17 -04:00
Jarrod Johnson f03bb36dbe Fix nodeconfig treatment of bmc attributes
Make bmc behave like other categories/settings.
2019-08-29 15:24:14 -04:00
Jarrod Johnson 97a950b145 Retain XCC IP on discovery if already set
Do not change from DHCP if DHCP is working the way intended.
2019-08-28 09:46:35 -04:00
Jarrod Johnson a0e445d1b1 Force MSS down for forwarded connections
Some endpoints may not be able to fully handle the natural
MSS suggested by MTU.
2019-08-28 09:16:42 -04:00
Jarrod Johnson 65629548c9 Add support for new BMC config capabilities
This enables nodeconfig -r bmc and nodeconfig bmc.<attr> function.
2019-08-27 14:56:19 -04:00
Jarrod Johnson 6cfbf4533c Add support for BMC clear and extended attributes
This wires up new function in pyghmi.
2019-08-27 14:32:16 -04:00
Jarrod Johnson 5794dd7f8c Add CP storage to discovery 2019-08-22 16:15:01 -04:00
Jarrod Johnson 48fa74e7a9 Explicitly use utf8 when encode error encountered
Some platforms do not naturally do utf-8.  This is
pretty much always the answer, so try it if the default
encoding of a platform fails.
2019-08-22 08:57:47 -04:00
Jarrod Johnson 59d5110b8f Also enable ipmi if user sets in console.method 2019-08-20 09:29:25 -04:00
Jarrod Johnson 051d79727b Fix sysvinit
sysvinit lsb function is 'status_of_proc'
2019-08-20 08:59:01 -04:00
Jarrod Johnson 4cdbc7807b Add thinkagile storage to discovery
At least enumerate the ipv4 pieces.
2019-08-19 16:37:14 -04:00
Jarrod Johnson feecee82db Mitigate excessive open web sessions
Back to back discovery testing would exhaust web slots.
Severely mitigate through being more aggressive about logging out.
2019-08-19 10:44:47 -04:00
Jarrod Johnson 395c0d4697 Preserve IPMI state unless user wants otherwise
ALso a draft of navigating a forced password change
in the midst of a pre-hashed password conversion.
2019-08-16 16:33:57 -04:00
Jarrod Johnson a963a8ca35 Handle forced password change and no IPMI for XCC
XCC firmware will start mandating a password change before use.

Additionally, IPMI will be unavailable and will be needed for enabling SMM.

TODO:
-Discover USERID/TempW0rd42 nodes that weren't preconfigged

-Enable IPMI on non-SD530 if hardwaremanagement.method is not redfish.
2019-08-15 16:40:15 -04:00
Jarrod Johnson d95464df6f Add a non-ip network string xmit concept 2019-08-08 16:14:05 -04:00
Jarrod Johnson 3f6e6d4c39 Support unavailable sensors in redfish 2019-08-08 15:02:26 -04:00
Jarrod Johnson c3176ab86a Add blink and identify reporting to redfish 2019-08-05 16:22:50 -04:00
Jarrod Johnson 4dab5fc527 Adapt to RHEL or Debian openssl config locations 2019-08-05 16:16:42 -04:00
Jarrod Johnson 8897842fc4 Fix SMM handler when None bmc
This fixes a common scenario for using fe80 collection
2019-07-26 13:50:59 -04:00
Jarrod Johnson a251a538b0 Improve SMM discovery
SMM discovery behavior has seemingly gotten more picky with time.
First switch to an IPMI-free if the user has custom password.  The
web based approach is much less problematic than SMM IPMI stack in
this context.

If user specifies they want to use default credentials, we have
no choice but to use IPMI.  Omit things and shuffle order of operations
to mitigate problems.  It isn't perfect, but it does work eventually.
2019-07-26 09:25:19 -04:00
Jarrod Johnson 480a747dcf Merge branch 'master' of github.com:jjohnson42/confluent 2019-07-25 13:10:08 -04:00
Jarrod Johnson af025f7304 Present log name when provided in nodeeventlog
Some managers combine logs, allow disambiguation through including in output.
2019-07-25 13:09:52 -04:00
Jarrod Johnson 21edd82177 Extend generic catches in redfish/ipmi
Have it provide more detailed error data at
a glance to short out some debug requirements.
2019-07-25 09:28:55 -04:00
Jarrod Johnson 8641885f86 Fix handling of socket error with neighbor
If a system is half up, a different sort of timeout is given.
Handle this and also preserve the original exception better
if not one of these two.
2019-07-25 08:52:47 -04:00
Jarrod Johnson 64cc2416d1 Fix list argument 2019-07-24 15:37:01 -04:00
Jarrod Johnson 2787e1d862 Present more data about missing entries from assign csv
When doing an assign on csv, present all the missing entries
rather than stopping on the first.
2019-07-23 11:57:35 -04:00
Jarrod Johnson 514a121c15 Print license install errors when provided
When the service gives errors installing keys,
relay them to the user.
2019-07-22 11:21:31 -04:00
Jarrod Johnson 00ce48b046 Fix behavior for bad nodelicense arguments
Correctly show help and exit if unrecognized
parameter.
2019-07-22 09:27:31 -04:00
Jarrod Johnson 44929e7975 Fix printing of unicode to pipe
nodesensors would have a unicode error on pipe output.
2019-07-19 15:36:43 -04:00
Jarrod Johnson da82fef0cb Have nodelist use nodeattrib completion
Since nodelist may also show attribute values, use same completion function.
2019-07-19 14:22:19 -04:00
Jarrod Johnson efcac0b181 Fix nodesensors -n with csv 2019-07-19 14:12:40 -04:00
Jarrod Johnson 46e2f53018 Always use GCM on encrypt
Continue to support read using the old scheme, but even when
an integrity key is available, only use it to aid in decrypting
classic format, and always write in new format.
2019-07-17 08:51:06 -04:00
Jarrod Johnson cf51928b3d Implement GCM and close gap in the HMAC
When generating key material from scratch, skip HMAC and
activate GCM mode.

When using existing CBC/HMAC keys, start covering the IV value
in the HMAC.  For compatibility, HMAC validity is checked with
and without IV.
2019-07-16 18:32:23 -04:00
Jarrod Johnson 151ba2e567 Add error messages to nodeattrib clear
nodeattrib -c was not reporting useful error information.
2019-07-15 13:28:09 -04:00
Jarrod Johnson bc87077397 Fix error handling and consistency in networking
by-port specification was inconsistent and unhelpful in error between macmap and lldp.
2019-07-15 11:07:59 -04:00
Jarrod Johnson a77b65737e Suppress usage on nodefirmware error
It is very bizarre to have the usage output
after an error.
2019-07-12 12:10:22 -04:00
Jarrod Johnson 19c2963cf9 Fix reassign with SMM
SMM validation assumes an earlier connection, fix so that it will accept the certificate
if no certificate expected yet.
2019-07-11 15:55:20 -04:00
Jarrod Johnson a0ea8eeae3 Fix nodediscover support of bmc_gateway
The command expected spaces, but documentation
said underscore, support both old csvs and doc
compliant csvs.
2019-07-11 15:36:31 -04:00
Jarrod Johnson 6ad1ce4df5 Back off concurrent retrieval.
Some BMCs are incapable of handling concurrent requests.
This is a blow particularly to high latency management given
Redfish's tendency to require a lot of resource fetches, but
we don't have a particularly discoverable strategy for knowing
in advance whether an implementation is up for some optimization.
2019-07-11 11:41:42 -04:00
Jarrod Johnson c53264872a Fix scenario with undefined passlength
If passwordcomplexity were requested without a passwordlength,
things would be a problem.
2019-07-11 10:53:43 -04:00
Jarrod Johnson d9f2c0b266 Correct mistake in setting names 2019-07-11 10:40:49 -04:00
Jarrod Johnson d528d45820 Add configuration to opt into password policies. 2019-07-11 10:19:46 -04:00
Jarrod Johnson 4eeac8d71a Explore password evaluation as an option.
Password rules may be relevant to some scenarios.  In such a case, this
can provide guidance if the BMC does not have such a facility or
alternatively provide friendlier warnings than the BMC provides
around shortcomings of the password.
2019-07-10 15:32:47 -04:00
Jarrod Johnson 6cc0eb0797 Add reassign to nodediscover
Allow nodediscover to do 'reassign' to repeat discovery process for a discovered
node, without requiring an additional identifier.
2019-07-09 13:53:30 -04:00
Jarrod Johnson bfd0de1a4a Add expiration to more places 2019-07-09 13:26:48 -04:00
Jarrod Johnson a787ac62c3 Add expiration data from ipmi plugin
When pyghmi provides the information, enrich the return
data.
2019-07-09 12:48:56 -04:00
Jarrod Johnson fd9b4a8650 Add support for expiration data, when available 2019-07-09 10:55:33 -04:00
Jarrod Johnson 373bf3dca7 Remove stray whitespace
Fix formatting mistakes
2019-07-09 10:18:34 -04:00
Jarrod Johnson 0ad0c626c2 Restore password policy set to nodediscover
The shift away from IPMI had omitted the password policy set.
Amend the function and restore it to the sequence of events.
2019-07-08 16:25:07 -04:00
Jarrod Johnson fbc4fc6846 Make unexpected error more specific
Often a usable summary message is obfuscated.  Assume the subject line
is safe to relay, but continue to do a more verbose trace.
2019-07-08 14:28:56 -04:00
Jarrod Johnson 3efc153615 Improve conversion reliability
It was frequent that a token expiration would impact attempt to convert
an account.  Suppress the token based authentication to more reliably
have a fresh login.

Additionally, mitigate chance of exhausting user login limit.

Finally, switch to a generated password for the temporary account.  Should something go awry
between deleting the third-party account and recreating it, this
means the system will have to be reset through OS or F1 menu.  However this is better
than the risk of a well known backdoor account being inadvertently
created.
2019-07-03 11:39:36 -04:00
Jarrod Johnson b7ff093e48 Fix ubuntu package install location 2019-07-02 14:42:45 -04:00
Jarrod Johnson 7275e98039 Remove IPMI specific parameters to user
Users cannot have these settings in redfish
2019-07-01 11:23:28 -04:00
Jarrod Johnson 2b0c50dc23 Refresh connection parameters on retry
If the parameters changing cause a login failure,
take the opportunity to refresh that information to work
in the midst of a rediscover, for example.
2019-07-01 09:15:01 -04:00
Jarrod Johnson 54439d5f18 Fix cause of former 'login process died'
If a session died without calling logged, the confluent plugin
instance would be orphaned.  Detect this situation to trigger a
retry.
2019-07-01 09:05:08 -04:00
Jarrod Johnson 65b4cbe8cc Revised fix for redfish name missing case 2019-06-28 16:02:19 -04:00
Jarrod Johnson c8931ae6e7 Revert "Carry fix for null names to redfish"
This reverts commit 8bbeeafa49.
2019-06-28 16:01:26 -04:00
Jarrod Johnson 083f5c8654 Add python-dateutil rpm dependency 2019-06-28 15:41:17 -04:00
Jarrod Johnson 8bbeeafa49 Carry fix for null names to redfish 2019-06-28 15:14:59 -04:00
Jarrod Johnson 422f210f74 Handle adapters with null names
Under some situations, null names are given
for adapters, apply generic treatment to such
devices.
2019-06-28 15:13:56 -04:00
Jarrod Johnson 2e6029bd2c Add a location.height attribute
This permits user to specify height for either unsupported systems
or to speed up the rackview drawing.
2019-06-28 09:30:53 -04:00
Jarrod Johnson 81c0adbbe3 More python 3 compatibility fixes
Improve more commands and modules to parse and execute under python 3.
2019-06-28 08:51:57 -04:00
Jarrod Johnson 6d5f0cdb16 Make TCP_FASTOPEN opportunistic
Certain Linux-like but not Linux environments fail
at this.
2019-06-27 15:36:27 -04:00
Jarrod Johnson c633286019 Add missing dateutil dependency to apt 2019-06-27 15:31:00 -04:00
Jarrod Johnson ba113d6445 Fix various python2-isms
This is far from a complete python3 support, but it lets a significant volume
of remote commands run under python3
2019-06-27 15:28:59 -04:00
Jarrod Johnson d2efb16c71 Remove unneeded line 2019-06-27 15:21:35 -04:00
Jarrod Johnson 739e302506 Add an example for just disabling password complexity 2019-06-27 15:20:24 -04:00
Jarrod Johnson ae181b7753 Improve nodelicense error messages
Check and exit should the file or directory not exist.
2019-06-26 13:24:24 -04:00
Jarrod Johnson b76b415a6e Update nodelicense man page 2019-06-26 08:45:11 -04:00
Jarrod Johnson ef2b324eed Flush csv output per row
Improve responsiveness of csv output when piping
2019-06-25 11:03:50 -04:00
Jarrod Johnson ffe9606de1 Auto-repair 'login process died' condition
The cause is still unknown, but we should be able to at least
repair automatically.
2019-06-24 16:34:56 -04:00
Jarrod Johnson 8ed2d5a551 Fix confulent2xcat usage text
It was incorrectly referencing ansible.
2019-06-24 14:17:32 -04:00
Jarrod Johnson 3501b3c347 Add state info to all licenses
The all resource was not retrieving the licenses.
2019-06-21 15:52:24 -04:00
Jarrod Johnson e55314d759 Add display of inactive licenses
Inactive licenses are also an issue.
2019-06-21 10:17:52 -04:00
Jarrod Johnson 27410a9b6b Fix discover of XCC
Incorrect module path was indicated.
2019-06-20 10:56:09 -04:00
Jarrod Johnson 2db01746d5 Support deletion of licenses from XCC 2019-06-19 16:35:24 -04:00
Jarrod Johnson 208be0beef Implement nodelicense save
Add ability to save licenses from
the XCC.
2019-06-19 15:43:45 -04:00
Jarrod Johnson d34f8af798 Rework redfish support for user management
The redfish user management api couldn't quite be identical,
adjust to the changes.
2019-06-13 15:02:53 -04:00
Jarrod Johnson b2013e93c5 Mitigate performance impact of oem sensors
The sensormap was being regenerated each time a sensor
was asked for.  Make the sensor map
a more perisstent fixture.
2019-06-12 14:47:28 -04:00
Jarrod Johnson 2a72a6184d Fix confluent-wide pauses during redfish
The lenovo OEM module was unpatched in import and
thus it inflicted a confluent-wide sleep instead of
a patched time.sleep.
2019-06-12 10:16:19 -04:00
Jarrod Johnson 7e4dcfa99c Merge branch 'master' of github.com:jjohnson42/confluent 2019-06-11 11:07:31 -04:00
Jarrod Johnson ee82831370 Do not flag file: as insecure
Locally hosted media should not be considered
insecure.
2019-06-11 11:06:59 -04:00
Jarrod Johnson 0869669ef6 Better isolate system config fault
System configuration fault will now be contained to node.
2019-06-07 16:57:03 -04:00
Jarrod Johnson 6a77a13539 Improve error for unserializable collective data
XML errors turn out to be unserializable.  Catch this general
class of problems and provide a less devastating behavior.

Doing an xml.fromstring('') is an example of how to trigger it.
2019-06-07 16:47:17 -04:00
Jarrod Johnson 56e9a67ef8 Fix boundary issue on oversize file
If the logfile is large enough to cause
a struct.error, just force a size
roll and continue.

Also unconditionally unlock the file.
2019-06-07 15:54:12 -04:00
Jarrod Johnson 52d5eb9876 Add stripsize to the redfish plugin
Storage creation was not passing through the stripsize parameter.
2019-06-07 09:34:29 -04:00
Jarrod Johnson b819a488f1 Mirror hotspare handling from ipmi to redfish
The redfish plugin should handle the same disk information as ipmi plugin.
2019-06-06 15:13:19 -04:00
Jarrod Johnson 3fc31f7332 Add dedicated hot spare information
If an array contains dedicated hot spare, properly
report it alongside the member disks.
2019-06-06 11:37:30 -04:00
Jarrod Johnson 21c3579287 Add setdisk and stripsize
More nodestorage improvements.
2019-06-05 15:54:29 -04:00
Jarrod Johnson 4a094f669e Do not break for zsh users
The completion functionality shall be skipped
unless the shell is bash specifically.
2019-06-05 14:27:08 -04:00
Jarrod Johnson 67eecffd29 Force stripsize to numeric
This should be a numeric value, even if it came in as a string.
2019-06-05 11:22:35 -04:00
Jarrod Johnson e288e8bad5 Add stripsize to the input on volume
Explictly ensure a stripsize key.
2019-06-05 11:16:44 -04:00
Jarrod Johnson a8cad7a70f Add stripsize to API
Allow the caller to select a custom stripsize if desired.
2019-06-04 16:33:10 -04:00
Jarrod Johnson 6de605c298 Switch to python2/3 agnostic lower
The string.lower is not in python3
2019-06-04 16:27:20 -04:00
Jarrod Johnson e09c2ed8eb Support more convoluted detail
Some uefi settings details contain
more tricky detail information.
2019-06-03 15:30:32 -04:00
Jarrod Johnson cd5366e73f Fix nodeconfig for non-ascii choices 2019-05-31 14:47:07 -04:00
Jarrod Johnson 509f8c30d5 Remove use of IPMI in XCC config
The XCC configuration is now entirely
over https and well suited for an ipmi disabled scenario.
2019-05-31 08:50:36 -04:00
Jarrod Johnson c63c8076bb Use https to set network on XCC
This quite nearly completes the removal
of IPMI requirement during bootstrap.
2019-05-29 16:36:13 -04:00
Jarrod Johnson 6800c8055c Implement IPMI-free xcc config (work in progress) 2019-05-29 14:31:39 -04:00
Jarrod Johnson ffc55b1594 Reduce concurrency to redfish targets
Some redfish implementations did
not handle a relatively open ended barrage
of concurrent requests.  Try limitting to 4 concurrent
requests to evaluate how the implementations handle it.
2019-05-20 11:03:26 -04:00
Jarrod Johnson 481342340e Fix potential nodesensors crash
There is a tiny chance that time will tick between two
calls.  This fixes it.
2019-05-16 14:37:18 -04:00
Jarrod Johnson d33c6be758 Fix forwarder over custom https ports 2019-05-16 14:36:39 -04:00
Jarrod Johnson 44f3630cf5 Further amend formatting of nodestorage manual 2019-05-14 13:56:20 -04:00
Jarrod Johnson 3eaba23e6f Fix formatting of nodestorage man page 2019-05-14 13:53:28 -04:00
Jarrod Johnson 5ac0a6e650 Fix raid configuration for operator
Operator was not allowed to create arrays.
2019-05-14 10:42:42 -04:00
Jarrod Johnson 9ac83665c6 Isolate redfish node errors
If code experiences an issue specific to a node, isolate that fault to the node.
2019-05-13 14:37:47 -04:00
Jarrod Johnson 30f9d28c2c Merge branch 'master' of github.com:jjohnson42/confluent 2019-05-13 13:36:17 -04:00
Jarrod Johnson 0168e46f24 Isolate individual node errors in ipmi plugin
If an individual node experiences an unexpected error,
isolate the fallout to that specific node.
2019-05-13 13:35:03 -04:00
Jarrod Johnson 067e99d6ce Merge branch 'master' of github.com:jjohnson42/confluent 2019-05-10 14:56:48 -04:00
Jarrod Johnson ad828e609d Reduce bad default login tries
For an SD530 XCC, we would incur 4 attempts at default:
-To pre-config enable SMM, we try once
-Due to pyghmi auto-degrade, try again as oper
-Then during the actual config phase, try again
-Again, try again as oper

Now with pyghmi opt-out, we will force to try only as admin, eliminating the second try.

The SD530 code will now mark that the default creds failed so that
the config phase will know to skip that.
2019-05-10 14:34:39 -04:00
Jarrod Johnson cc5a5c9972 Fix operator add and delete of nodes
This permits operators to run nodedefine and noderemove.
2019-05-10 13:15:19 -04:00
Jarrod Johnson cd2361b80b Fix nodediscover clear for operators
Operators should be allowed to delete discovery data.
2019-05-10 13:11:04 -04:00
Jarrod Johnson c042583a64 Add support for CSV formatted data
Presume CSV semantics for input.
2019-05-10 11:08:12 -04:00
Jarrod Johnson e32d3cf4cc Add auto-index determination to stats
This allows it to auto-skip over units, for example.
2019-05-10 10:34:56 -04:00
Jarrod Johnson 2b86c878a8 Cleanly handle bad credentials in redfish
Provide a similar experience to the ipmi plugin.
2019-05-07 16:19:30 -04:00
Jarrod Johnson 3564de8c6d Fix web consoles/shells for operators
Operator role needed more permissions to act as expected.
2019-05-07 15:58:34 -04:00
Jarrod Johnson 7b5361a019 Add expressions to Operator role
noderun/nodeshell would not work for operators without this.
2019-05-03 09:06:20 -04:00
Jarrod Johnson 65e1dfcc57 Fix nodesensors with redfish plugin
redfish plugin does not produce the same data as ipmi,
tolerate that difference.
2019-05-02 10:54:15 -04:00
Jarrod Johnson ba039e9e3e Fix nodeeventlog on ipmi devices
Changes for redfish broke against ipmi plugin
2019-05-02 10:21:24 -04:00
Jarrod Johnson a6809aae98 Add Monitor role
Add a monitor role that is only viable for monitoring relevant
tasks.
2019-05-02 10:04:40 -04:00
Jarrod Johnson 4d5bfb13bf Add support for Operator role
Support a reduced privilege user that can still perform
most operations, but cannot modify, delete, or add
users/groups to confluent or to BMCs.
2019-05-01 16:57:15 -04:00
Jarrod Johnson 93e9a54e86 Relay redfish error strings to client
This provides a much better experience than 'unexpected'
error.
2019-05-01 11:46:02 -04:00
Jarrod Johnson 25028c8acc Merge branch '2.2.cme' 2019-05-01 09:18:09 -04:00
Jarrod Johnson 906c671d90 Fix misakes in usergroups
Deletion was incorrect and restore from json did not work.
2019-04-30 16:18:36 -04:00
Jarrod Johnson 8fbd99cf5c Fix misakes in usergroups
Deletion was incorrect and restore from json did not work.
2019-04-30 16:18:12 -04:00
Jarrod Johnson c86ac2885f Fix overly verbose log on client close
When a client would close (e.g. an unathenticated nodelist),
a large trace be logged.  Fix by returning silently in such a case.
2019-04-30 15:27:50 -04:00
Jarrod Johnson 952fa3d022 Add user groups to confluent
This allows a system/ldap group to be used instead of directly
specifying individual authorized users.
2019-04-30 15:27:41 -04:00
Jarrod Johnson 90e0f93d37 Module to assist with advanced user manipulation
Currently holds the logic to ascertain the system groups
for a system user.
2019-04-30 15:27:34 -04:00
Jarrod Johnson d78adc334d Fix overly verbose log on client close
When a client would close (e.g. an unathenticated nodelist),
a large trace be logged.  Fix by returning silently in such a case.
2019-04-30 15:03:55 -04:00
Jarrod Johnson 31f2161b57 Add user groups to confluent
This allows a system/ldap group to be used instead of directly
specifying individual authorized users.
2019-04-30 14:55:54 -04:00
Jarrod Johnson 571a34cba2 Module to assist with advanced user manipulation
Currently holds the logic to ascertain the system groups
for a system user.
2019-04-30 13:23:26 -04:00
Jarrod Johnson 52fa5158f6 Fix display of final bin members in verbose 2019-04-26 16:51:44 -04:00
Jarrod Johnson 907f66ae8b Have the range be more precise on verbose 2019-04-26 16:43:53 -04:00
Jarrod Johnson c8c275f804 Fix indentation error 2019-04-26 16:40:47 -04:00
Jarrod Johnson 7a08fee4b5 Actually fix the verbose range 2019-04-26 16:29:33 -04:00
Jarrod Johnson 36f0d888cd Fix the verbose output boundaries. 2019-04-26 16:17:28 -04:00
Jarrod Johnson 81451a6451 Add options to stats
Implement verbose, text plot, and custom select bins
2019-04-26 16:04:01 -04:00
Jarrod Johnson 02eb195e3f Change topline of script to be consistent 2019-04-25 14:47:20 -04:00
Jarrod Johnson 87e7a90c37 Move stats into the client
stats is good enough to be promoted from prototype to a confluent
client component.
2019-04-25 14:46:18 -04:00
Jarrod Johnson bafc25005f Flesh out stats with arguments 2019-04-25 14:45:47 -04:00
Jarrod Johnson 33c1137ccf Remove use of tmp file in stats 2019-04-25 13:59:15 -04:00
Jarrod Johnson abfeef5a0a Merge branch '2.2' 2019-04-25 13:53:41 -04:00
Jarrod Johnson e81579f414 Add a prototype stats command for CLI commands 2019-04-25 13:53:34 -04:00
Jarrod Johnson 47edb1dbd1 Add a prototype stats command for CLI commands 2019-04-25 13:51:50 -04:00
Jarrod Johnson 6a8cb8deaa Merge branch '2.2' 2019-04-22 13:17:16 -04:00
Jarrod Johnson c6516f9d62 Support redfish event logs 2019-04-22 12:54:49 -04:00
Jarrod Johnson 72448aa0b4 Disable MIB resolution for raw requests
MIB resolution turns out to be rather CPU intensive, and the
current SNMP consumers don't want the resolution anyway.
2019-04-16 08:49:32 -04:00
Jarrod Johnson 6290c169f5 Disable MIB resolution for raw requests
MIB resolution turns out to be rather CPU intensive, and the
current SNMP consumers don't want the resolution anyway.
2019-04-16 08:46:50 -04:00
Jarrod Johnson e5bbd226ff Add completion for attributes in node*attrib
Make some of the tedium of the long attribute names bearable
through tab completion.
2019-04-15 14:01:59 -04:00
Jarrod Johnson 037ed43c70 Merge branch 'master' of github.com:jjohnson42/confluent 2019-04-15 13:48:20 -04:00
Jarrod Johnson 0a816acf4f Add completion for attributes in node*attrib
Make some of the tedium of the long attribute names bearable
through tab completion.
2019-04-15 13:38:56 -04:00
Jarrod Johnson 2c9c778ca7 Fix compatibility without module_type
Some vendors do not provide module_type
value.  For such vendors, simply omit
the information rather than fail.
2019-04-15 11:08:56 -04:00
Jarrod Johnson bf005eace6 Merge branch 'master' of github.com:jjohnson42/confluent 2019-04-11 16:27:13 -04:00
Jarrod Johnson 34c6d6a4d7 Choose an easier name for the reader 2019-04-11 16:26:59 -04:00
Jarrod Johnson b402ddd656 Add more keystrokes and easier use
No longer require cbl file be specified manually.
2019-04-11 16:26:14 -04:00
Jarrod Johnson 1ae055fa8f Add '-n' option to nodeshell and noderun
Provide ability to suppress node prefix for nodeshell.
This for example can be a quick 'makehosts' substituted and
similar.
2019-04-11 09:18:37 -04:00
Jarrod Johnson 89cf255ae7 Add '-n' option to nodeshell and noderun
Provide ability to suppress node prefix for nodeshell.
This for example can be a quick 'makehosts' substituted and
similar.
2019-04-11 09:17:38 -04:00
Jarrod Johnson c070148aed Fix adequate check on inadequate IMMs 2019-04-08 10:15:27 -04:00
Jarrod Johnson d6097ca706 Merge branch 'master' of github.com:jjohnson42/confluent 2019-04-08 10:15:10 -04:00
Jarrod Johnson c3eed19309 Fix adequate check on inadequate IMMs 2019-04-08 10:14:49 -04:00
Jarrod Johnson 40dbe63336 Script to disable password expiry after expired on SMM 2019-04-05 16:53:32 -04:00
Jarrod Johnson d6ecee955b Skip empty nodes list
A noderange based nodegroup would have
the empty nodes list cluttering the output.
Skip empty nodes list in current settings.
2019-04-05 09:37:14 -04:00
Jarrod Johnson d7d3ae344c Skip empty nodes list
A noderange based nodegroup would have
the empty nodes list cluttering the output.
Skip empty nodes list in current settings.
2019-04-05 09:17:45 -04:00
Jarrod Johnson 5c4944a1e4 Provide a sample script for fixing expired credentials 2019-04-05 08:37:31 -04:00
Jarrod Johnson 06b31f4845 Add man page for collective command 2019-04-04 10:18:34 -04:00
Jarrod Johnson 7fecd0ac5c Add man page for collective command 2019-04-04 10:18:06 -04:00
Jarrod Johnson 36d5d60edc Autofill collective.manager on discovery if not set
To improve the ease of use, if an administrator has a collective but
does not designate a collective.manager for a node being discovered,
default to the collective member that executes the discovery.
2019-04-04 09:50:26 -04:00
Jarrod Johnson 6e26b19c67 Autofill collective.manager on discovery if not set
To improve the ease of use, if an administrator has a collective but
does not designate a collective.manager for a node being discovered,
default to the collective member that executes the discovery.
2019-04-04 09:49:02 -04:00
Jarrod Johnson 16430e1ec9 Enhance collective usage output
Collective usage output provided no hints as to how to access more detailed
help.  Amend the wording to make this more clear/obvious.
2019-04-03 14:23:50 -04:00
Jarrod Johnson 5d572f17f9 Enhance collective usage output
Collective usage output provided no hints as to how to access more detailed
help.  Amend the wording to make this more clear/obvious.
2019-04-03 14:23:30 -04:00
Jarrod Johnson ae49cf290e Fix key hold-down behavior in cbl reader
The retry print could get stuck in loop and the input
could queue up too many keypresses.
2019-04-03 11:44:05 -04:00
Jarrod Johnson 5ead803c8a Fix up the injected clear delimiting
The delimiting was not being navigated correctly.
2019-04-03 10:38:35 -04:00
Jarrod Johnson 7232a0c1b3 Fix SLP hangs on bad targets
Have SLP timeout if there are endpoints that can half-hang
a connection.
2019-04-03 08:35:25 -04:00
Jarrod Johnson dce25d802e Fix SLP hangs on bad targets
Have SLP timeout if there are endpoints that can half-hang
a connection.
2019-04-03 08:34:42 -04:00
Jarrod Johnson 835d1fc0ab Update the pyopenssl message
It makes it more clear that a restart would be
required to pull in updated dependency.
2019-04-02 09:40:18 -04:00
Jarrod Johnson c28a963d62 Update the pyopenssl message
It makes it more clear that a restart would be
required to pull in updated dependency.
2019-04-02 09:39:06 -04:00
Jarrod Johnson 9fd091daad Tolerate an XCC with downed web service
Make the best of the situation by trying to continue
without the policy applied.
2019-04-02 09:37:33 -04:00
Jarrod Johnson 3c21ca8739 Tolerate an XCC with downed web service
Make the best of the situation by trying to continue
without the policy applied.
2019-04-02 09:36:37 -04:00
Jarrod Johnson 996b1ba45b Rework prototype cbl reader
It is still not right, but it is a bit easier to work with
to figure out what's wrong with it.
2019-04-01 16:56:14 -04:00
Jarrod Johnson 4af1f998fb Fix nodeconfig formatting
The man page did not have a hard line break.
2019-04-01 14:19:18 -04:00
Jarrod Johnson b2c1137321 Fix nodeconfig formatting
The man page did not have a hard line break.
2019-04-01 14:16:20 -04:00
Jarrod Johnson d484e9db43 Update log.py comment for accuracy
The metadata format was out of date.
2019-04-01 10:35:20 -04:00
Jarrod Johnson 6397709e47 Try to force split across clear screens 2019-03-29 17:07:01 -04:00
Jarrod Johnson e0c0f0f1f3 Greatly flesh out the cbl reader 2019-03-29 16:01:40 -04:00
Jarrod Johnson ca29f6ae35 Opportunisticly start mac rescan on rescan
While the network rescan might be too slow to hold up
general rescan, at least begin a rescan of switches
when a rescan is requested.
2019-03-29 14:03:00 -04:00
Jarrod Johnson 2c8681a9f3 Opportunisticly start mac rescan on rescan
While the network rescan might be too slow to hold up
general rescan, at least begin a rescan of switches
when a rescan is requested.
2019-03-29 14:01:36 -04:00
Jarrod Johnson b927572872 Sample file for processing CBL files 2019-03-29 11:17:05 -04:00
Jarrod Johnson b5df380ee4 Update nodeinventory for redfish memory
Redfish doesn't present some data that was in the IPMI spec
2019-03-28 13:37:13 -04:00
Jarrod Johnson 5c61430ccc Add wildcard documentation to noderange man page. 2019-03-28 11:15:28 -04:00
Jarrod Johnson 2b275cd369 Add wildcard documentation to nodeattrib/nodelist 2019-03-28 11:15:23 -04:00
Jarrod Johnson f79dac7bd2 Add wildcard documentation to noderange man page. 2019-03-28 11:14:29 -04:00
Jarrod Johnson fc5f16fb01 Add wildcard documentation to nodeattrib/nodelist 2019-03-28 11:12:36 -04:00
Jarrod Johnson 907d25164f Replace the network error with a local error
This is a bit more clear about the cause when local commands fail.
2019-03-28 11:03:57 -04:00
Jarrod Johnson 0b85fab529 Replace the network error with a local error
This is a bit more clear about the cause when local commands fail.
2019-03-28 11:03:33 -04:00
Jarrod Johnson adb4ce919e Fix nodegrouplist man page 2019-03-28 10:14:30 -04:00
Jarrod Johnson 9379c85d0e Fix nodegrouplist man page 2019-03-28 10:05:35 -04:00
Jarrod Johnson 11ffa7a091 Fix debian build process 2019-03-26 13:50:15 -04:00
Jarrod Johnson bacba8972a Fix debian build process 2019-03-26 13:49:54 -04:00
Jarrod Johnson 5404497e70 Change wheezy to depend on old package name 2019-03-26 13:47:06 -04:00
Jarrod Johnson 70690517de Change wheezy to depend on old package name 2019-03-26 13:46:39 -04:00
Jarrod Johnson a3162daf62 Skip pushing static config if config already matches
A strategy of manually adding DHCP managed nodes produced static-baking
when not desired.  For now skip the baking in if the address matches.
2019-03-26 13:44:24 -04:00
Jarrod Johnson 8c886b751c Skip pushing static config if config already matches
A strategy of manually adding DHCP managed nodes produced static-baking
when not desired.  For now skip the baking in if the address matches.
2019-03-26 13:43:30 -04:00
Jarrod Johnson 69630edfa9 Handle more generics from Lenovo Redfish
Several generics can come back for adapters, handle them to trigger
pcie enhanced lookup.
2019-03-25 15:45:36 -04:00
Jarrod Johnson cdce1f1833 Add concurrency pool to pyghmi usage
pyghmi adds pool for concurrency, utilize that to accelerate operations
that need multiple resources in parallel.
2019-03-22 15:56:58 -04:00
Jarrod Johnson 48079f297b Change wheezy name to python-confluent... 2019-03-19 15:03:41 -04:00
Jarrod Johnson bf24d0f501 Change wheezy name to python-confluent... 2019-03-19 15:03:06 -04:00
Jarrod Johnson 1d6111b8dd Merge branch 'master' of github.com:jjohnson42/confluent 2019-03-18 15:02:55 -04:00
Jarrod Johnson e59d237d11 Add draft redfish plugin
It can do power, system config, set boot device, identify.
2019-03-18 15:02:21 -04:00
Jarrod Johnson fb3dc9a200 Merge branch 'master' of github.com:jjohnson42/confluent 2019-03-14 13:07:09 -04:00
Jarrod Johnson b0d2d44b75 Update to follow DCD
The DCD signal can be used to detect remote connect attempt
2019-03-14 13:05:59 -04:00
Jarrod Johnson f1e83d938b Add carrier detect to autocons sample
For genesis, not necessarily relevant, but may be
very relevant for OS behaviors in other contexts.
2019-03-14 09:33:58 -04:00
Jarrod Johnson e643b7ed7d Remove inadvertent duplicate command
Harmless, but should be removed.
2019-03-13 15:13:13 -04:00
Jarrod Johnson 163b29a07c Update autocons.py
This is the version that landed in xCAT genesis
2019-03-13 15:05:42 -04:00
Jarrod Johnson c5fa0bfd79 Draft attempt at autocons utility
Make every effort to do early boot console enablement.
2019-03-12 19:31:16 -04:00
Jarrod Johnson a258653186 Merge branch 'master' of github.com:jjohnson42/confluent 2019-03-11 09:08:28 -04:00
Jarrod Johnson 656e82c3fe Speed up cnos health and add stubs
Add concurrency to accelerate nodehealth and provide stubs
for the as-yet unimplemented functionality.
2019-03-08 16:05:42 -05:00
Jarrod Johnson 898ff065e0 Merge branch 'master' into umaster 2019-03-08 16:04:19 -05:00
Jarrod Johnson 779b5c9ede Speed up cnos health and add stubs
Add concurrency to accelerate nodehealth and provide stubs
for the as-yet unimplemented functionality.
2019-03-08 16:02:52 -05:00
Jarrod Johnson 5be08ddb1d Fix missing sub-health info on CNOS health 2019-03-08 13:38:38 -05:00
Jarrod Johnson 16abf7cb64 Fix missing sub-health info on CNOS health 2019-03-08 13:38:15 -05:00
Jarrod Johnson 269acf9943 Add CNOS plugin for Lenovo switches 2019-03-08 13:26:34 -05:00
Jarrod Johnson c649ae5fec Have it appropriate do IPv4 and IPv6 2019-03-08 13:25:53 -05:00
Jarrod Johnson c3f2e131b2 Add CNOS plugin for Lenovo switches 2019-03-08 13:25:04 -05:00
Jarrod Johnson 4124e0fcc0 Add ability for noderange to wildcard attrib names
Useful for net.*attribs to search when nic is unknown.
2019-03-07 15:20:19 -05:00
Jarrod Johnson 0e2e6267cd Add ability for noderange to wildcard attrib names
Useful for net.*attribs to search when nic is unknown.
2019-03-07 15:19:17 -05:00
Jarrod Johnson e8119d330d Add IPv4 search to copernicus search 2019-03-07 10:24:26 -05:00
Jarrod Johnson 5ae6717709 Rename findconfluent 2019-03-07 08:57:52 -05:00
Jarrod Johnson 0cd94447f7 Update to search multiple interfaces 2019-03-06 16:48:37 -05:00
Jarrod Johnson ce4f8c1837 Sample C code for locating confluent server 2019-03-06 16:22:55 -05:00
Jarrod Johnson 8ad06f79e7 Add nodersync
This provides bulk transfer with status to a noderange.
2019-03-04 14:28:52 -05:00
Jarrod Johnson 5481da269e Merge branch 'master' into 2.2 2019-03-01 15:27:40 -05:00
Jarrod Johnson 6ea307d415 Add nodegrouprename command 2019-03-01 15:27:13 -05:00
Jarrod Johnson 59aa23b2f5 Add noderename command 2019-03-01 15:21:29 -05:00
Jarrod Johnson 4446308030 Add ability to rename nodegroups
If we can rename nodes, should be able to rename groups.
2019-03-01 15:03:43 -05:00
Jarrod Johnson 7703c6c2ab Enable Server Portion of renamae node
This plumbs up through the messages and attributes plugin.
2019-03-01 14:37:07 -05:00
Jarrod Johnson f5b6d434f3 Fix node collection function signature 2019-03-01 13:37:13 -05:00
Jarrod Johnson 8ce5a7dccf Phase 1 of node rename support
Provide foundation for node renaming, including
updating groups and inheritance and notifying collection
watchers of the change, and updating the existing watchers
with the new notification fingerprint.
2019-03-01 13:21:57 -05:00
Jarrod Johnson 23c9e6315a Update node collection handlers for renamed
Rename support will provide a map of old to new name.  Have the
existing node collection watchers accept a new argument.
2019-02-28 15:57:35 -05:00
Jarrod Johnson 38f9583be3 Implement direct add switches
Allow addition of switches without associated
nodes.  This allows populating mac database
without requiring associated nodes.
2019-02-28 13:00:12 -05:00
Jarrod Johnson 1b355ec468 Merge branch 'master' of github.com:jjohnson42/confluent 2019-02-28 12:59:52 -05:00
Jarrod Johnson 2bbf4b9e98 Implement direct add switches
Allow addition of switches without associated
nodes.  This allows populating mac database
without requiring associated nodes.
2019-02-28 12:59:41 -05:00
Jarrod Johnson 1248894cf3 Amend nodegrouplist command 2019-02-28 10:24:24 -05:00
Jarrod Johnson c43365d2dd Merge pull request #102 from andywray/master
Add nodegrouplist

Will fix after merge
2019-02-28 10:17:43 -05:00
Jarrod Johnson 4e7c098e75 Remove stub of unimplemented set
nodestorage set for manipulating hotspare
and jbod was not done in time.
2019-02-28 09:16:25 -05:00
Jarrod Johnson ef6c89b883 Add man page for nodestorage 2019-02-28 09:13:57 -05:00
Jarrod Johnson 99c06813d9 Fix clearing validated attributes
Attributes that are validated can come
in as None to clear them, accept this
as valid as well.
2019-02-27 14:58:26 -05:00
Jarrod Johnson 686b59c2b4 Friendlier error on read during update
Firmware update error now sends a more friendly error to client.
2019-02-26 16:40:06 -05:00
Jarrod Johnson 46b909c291 Document nodesupport download behavior
nodesupport downloads locally, and does
not send through the client.  Document
the consequence of this for now.
2019-02-26 16:26:07 -05:00
Jarrod Johnson 9abb163c7e Merge branch 'master' of github.com:jjohnson42/confluent 2019-02-26 15:27:23 -05:00
Jarrod Johnson 7e25dd805f Update nodesupport usage
servicedata is, as yet, mandatory
2019-02-26 15:27:07 -05:00
Jarrod Johnson 31220292e5 Try debian build with minimum on breaks/replaces 2019-02-26 14:22:19 -05:00
Jarrod Johnson 161cf37f46 Fix nodediscover order and csv together 2019-02-26 13:57:11 -05:00
Jarrod Johnson ad64cda249 Rework transition package logic 2019-02-26 13:39:11 -05:00
Jarrod Johnson db812ac292 Specify confluent client deb name 2019-02-26 13:02:04 -05:00
Jarrod Johnson a322118877 Fix debian build 2019-02-26 11:09:23 -05:00
Jarrod Johnson ebfbbcca23 Fix reference to the logger class 2019-02-26 10:21:12 -05:00
Jarrod Johnson 275525d3f3 Add pointer to omitted option 'all'
Nodegroupattrib can take all as an argument, show it in usage.
2019-02-25 15:27:55 -05:00
Jarrod Johnson 938a6e44df Add checking for noderange conflict
A confluent nodegroup may either be a normal static one, which
can be used for attribute inheritence, or a dynamic one, which
cannot be used with static list or static attributes.

Warn the user when they try to set that up to make it more obvious
that the dynamic groups can't do what they are trying to do.
2019-02-25 15:23:54 -05:00
Jarrod Johnson ca6b203a09 Format console message
The message wrapping was very hard to read
on a default 80 wide terminal.
2019-02-22 10:28:10 -05:00
Jarrod Johnson c478cb5d6e Update language of empty buffer warning
It was confusing and failing to point out
possibilities that were frequently occuring.
2019-02-22 09:36:25 -05:00
Jarrod Johnson ca9e7d1d93 Attempt to catch filesystem full condition
Provide a more obvious behavior when filesystem fills
to explain confluent behavior in this situation.
2019-02-21 16:32:37 -05:00
Jarrod Johnson 2691722f48 Update usage example in nodeconfig
Provide a customized usage string to more accurately show
the structure of a nodeconfig command.
2019-02-21 15:02:53 -05:00
Jarrod Johnson e194222553 Capture trace data on firmware update failure
In the event of an unanticipated firmware exception,
capture to log.  Expected error conditions should have specific handlers
to avoid the tracellog treatment.
2019-02-21 14:40:32 -05:00
Jarrod Johnson 8f611f0e59 Advertise package name change
Have the new package name change in
control to prompt upgrade to do
the right thing.
2019-02-21 10:46:53 -05:00
Jarrod Johnson 1fdcf19563 Merge branch 'master' of github.com:jjohnson42/confluent 2019-02-20 14:13:59 -05:00
Jarrod Johnson add1a1b32a Add noderange to nodegroupattrib
noderange attribute on group was not
being presented by nodegroupattrib all.
Add the attribute explicitly to handle the
discrepency.
2019-02-20 14:13:48 -05:00
Jarrod Johnson 8abe384e1a Add notation in expression page about shell conflict 2019-02-14 19:29:56 -05:00
Andy Wray 14577be963 Add nodegrouplist 2019-02-13 15:36:59 -05:00
Jarrod Johnson e6b8d0dabc Make dependencies adaptable for wheezy and non-wheezy
Newer distributions we have different requirements.
2019-02-12 16:18:21 -05:00
Jarrod Johnson b1a91ad409 Add support for comments in batch
Use # as comment character in nodeconfig batch.
2019-02-12 11:12:47 -05:00
Jarrod Johnson 996fd82920 Provide quality output on list output/default
The output is better than default python treatment of list formatting.
2019-02-12 10:09:07 -05:00
Jarrod Johnson 5e6c66826f Provide error on useless api call
If making an api call against a noderange to set attributes and that noderange is blank,
provide feedback to help user know that
nothing happened.
2019-02-11 16:01:30 -05:00
Jarrod Johnson 22d79867c8 Reorganize builddeb to preserve git tree
The git tree is needed to successfully build
2019-02-11 15:16:24 -05:00
Jarrod Johnson 52d25d563b Correct spelling error in builddeb 2019-02-11 14:47:22 -05:00
Jarrod Johnson 68eeb95ea3 Ensure directory exists prior to use 2019-02-11 14:06:28 -05:00
Jarrod Johnson 95d5ff6a4c Have builddeb move to tmp
This avoids build trampling current working tree.
2019-02-11 13:54:49 -05:00
Jarrod Johnson b42114bea0 Actually apply sed to file
The sed was failing to save result to disk.
2019-02-11 11:20:59 -05:00
Jarrod Johnson e0877bc0b1 Workaround older python lack of SSLEOFError
Older python does nat have this exception,
stub it out for older python.
2019-02-11 11:00:47 -05:00
Jarrod Johnson 5289d34206 Fix the exception name in previous commit. 2019-02-11 10:56:29 -05:00
Jarrod Johnson f7f8247d02 Fallback to older eventlet signature
Older eventlet did not understand some arguments
on wsgi.  Fallback to not using those arguments
if unavailable.
2019-02-11 10:51:56 -05:00
Jarrod Johnson 57e23a6f52 Add missing dependencies to debian builds
Debian builds currently lean on py2dsc, but misses a few key
dependencies.
2019-02-11 10:09:02 -05:00
Jarrod Johnson 73b234d29e Support pre-cryptography paramiko
Older paraiko may be in use that does
not have cryptography requirement, address
error by only conditionally checking cryptography.
2019-02-08 14:43:20 -05:00
Jarrod Johnson bfe55e276d Do not try to delete a node if not in discovery data
This could produce undesired traces
2019-02-06 09:19:55 -05:00
Jarrod Johnson 44bcca99b6 Delete discovery entries related to deleted node
On node deletion, it can be confusing if a stale discovery
entry persists.  Delete such entries upon deletion.
2019-02-06 09:15:51 -05:00
Jarrod Johnson 4cb595684e Fix debian package name 2019-02-05 15:41:03 -05:00
Jarrod Johnson b153a14ff3 Have builddeb build names consistent with RPM
The deb package names and locations were inconsistent
with the RPM based distributions.  Correct this behavior.
2019-02-05 13:12:35 -05:00
Jarrod Johnson b620838189 Move rather than copy output debs 2019-02-05 10:36:06 -05:00
Jarrod Johnson 4540354ff2 Add optional location for builddeb 2019-02-05 10:29:31 -05:00
Jarrod Johnson 74963a73cc Do cd in the correct location 2019-02-04 15:35:55 -05:00
Jarrod Johnson 9fe200b525 Make sure builddeb goes to top of dir before cleanup 2019-02-04 15:16:52 -05:00
Jarrod Johnson b07d4e9736 Clean up extracted directory on successful deb 2019-02-04 15:14:39 -05:00
Jarrod Johnson f649efa110 Add script to build .deb
Easier support for debian and ubuntu.
2019-02-04 15:05:36 -05:00
Jarrod Johnson 521013e50a Implement SMM password policy configuration
The discovery.passwordrules is extended to support the SMM
2019-02-01 15:42:44 -05:00
Jarrod Johnson 25c8f93336 Provide error in the console when console.method is unset
This was a common mistake, and warranted a more blatantly obvious
output.
2019-02-01 12:49:00 -05:00
Jarrod Johnson 59f00dd10b Set password before access
In at least one scenario, we want the password to be squared away
before we start manipulating the user access level.
2019-01-31 15:59:49 -05:00
Jarrod Johnson 2e93af9b5e Treat '' same as None for plugin specification
From the CLI, both are the same and there is no good reason to
treat them differently from each other.
2019-01-31 15:58:57 -05:00
Jarrod Johnson 337ab3b1a0 Merge branch 'master' of github.com:jjohnson42/confluent 2019-01-31 14:29:03 -05:00
Jarrod Johnson f4cf74b699 Fix modifying dictionary while iterating
Need to make a stable value before iterating to delete.
2019-01-31 14:28:45 -05:00
Jarrod Johnson 085981f74c Remove spurious debug output
Some spurious debug output was injected by mistake.
2019-01-30 13:45:38 -05:00
Jarrod Johnson 8a5f1c6dc5 Parse string arguments to nodes attributes as noderange
Since everywhere else accepts noderange, it is a reasonable
expectation for the nodes attribute on nodegroups to also
take a noderange.  Correct this inconsistency.
2019-01-30 09:55:38 -05:00
Jarrod Johnson 09cb6963f0 Add attempt to present status data
tcons made this attempt, also implement this on a best
effort basis.
2019-01-29 16:02:54 -05:00
Jarrod Johnson 188feec0b4 Repair if transactioncount exists but wrong size
If filesystem is full, this could be a side effect that would impact
a later start in a collective context.  This mechanism induces repair
from a collective peer.
2019-01-28 16:20:07 -05:00
Jarrod Johnson 1902a333ae Rework audit on unix socket
Capture root in audit and be consistent about audit skipping between
socket and http.
2019-01-28 15:03:45 -05:00
Jarrod Johnson f6c46ddcb8 Fix checking causing breaking of setting empty
Empty values are always valid, do not check those.
2019-01-24 11:18:40 -05:00
Jarrod Johnson e23253815c Fix checking code with custom fields
For custom fields, do not cause an unexpected errors.  The lookup on the
validattrs will now default to nothing found instead of error.
2019-01-24 11:07:58 -05:00
Jarrod Johnson d979d29b0b Implement checking of input attributes
For attributes that have a well known set of inputs, provide the
data to the messages layer to provide a useful error to the user.
2019-01-22 16:02:17 -05:00
Jarrod Johnson bca676ed15 Have nodestorage assume show if no args
Confluent commands with noderange generally
assume 'get' if no option.  Be compliant with
this consistency.
2019-01-18 14:54:55 -05:00
Jarrod Johnson deed8b4b9b Fix behavior of SSDP discovery handler
It was not tracking multiple peers and it was also
extending the scan longer than needed.
2019-01-17 11:37:09 -05:00
Jarrod Johnson 2c94a10e23 Add complexity and reuse rules to discovery
Discovery can now relax two more common policies that have users
wanting to disable them.
2019-01-17 11:02:05 -05:00
Jarrod Johnson 299181223e Add '-b' option for collate
It was requested to be able to designate the 'reference' node for '-d'
comparison.  This implements that request.
2019-01-17 10:35:22 -05:00
Jarrod Johnson 1378b01feb Fix nodeconfig handling of multiple colons
If multiple colon designated settings are present, correctly
associate settings with appropriate key.
2019-01-16 11:31:06 -05:00
Jarrod Johnson 18713797b9 Fix pane splitting with large numbers of nodes
The tcons logic to select layout each iteration is now replicated,
to avoid too-small panes.
2019-01-15 16:00:39 -05:00
Jarrod Johnson 6588ac0990 Fix nodereseat false success message
nodereseat was reporting success when failure was actually encountered.
Address by injecting the node specific error.
2019-01-15 11:51:43 -05:00
Jarrod Johnson efd13c960f Add man page for nodelicense 2019-01-14 16:08:48 -05:00
Jarrod Johnson 4f14de0136 Add nodelicense command
This provides Bash access to the license management features.
2019-01-14 16:06:13 -05:00
Jarrod Johnson 6cecf6635c Merge branch 'master' of github.com:jjohnson42/confluent 2019-01-14 16:02:37 -05:00
Jarrod Johnson 5b7807fe3d Add nodelicense command
This provides Bash access to the license management features.
2019-01-14 16:02:15 -05:00
Jarrod Johnson 5f52ee9578 Support unique filenames through attribute expansion
Particularly in trying to support license keys, serial number
handling is at least required.  Easiest and most powerful and most
consistent path is to use the same attribute expansion as everywhere
else.
2019-01-14 15:41:17 -05:00
Jarrod Johnson 88275f5110 Fix xcc handler on incomplete data
A datum may come in without an attribute member at all.  Treat
this as 'false', obviously.
2019-01-14 15:37:04 -05:00
Jarrod Johnson 55c5bff0f9 Add support for uploading a license key
This provides the most important piece of license key management.
2019-01-14 15:09:49 -05:00
Jarrod Johnson 3782127590 Implement retrieving license info from XCC
With changes to pyghmi, we can now get license data.  Prepare
API to provide information about the licenses.
2019-01-14 14:55:03 -05:00
Jarrod Johnson 74355bd6f9 Merge branch 'master' of github.com:jjohnson42/confluent 2019-01-14 09:17:01 -05:00
Jarrod Johnson bc995520b7 Fix confetty tab completion
The refactoring to main caused scope of readline to be incorrect.
Pulled the scope back into namespace.
2019-01-14 09:15:59 -05:00
Jarrod Johnson 2d63e68494 Enable support for TCP_FASTOPEN
It might matter in some context.
2019-01-10 15:17:34 -05:00
Jarrod Johnson ceba3ff34f Fix remote collective console
The changes to support size data for ssh was not carried fully
through the proxyconsole object.  Fix this support.
2019-01-09 11:34:19 -05:00
Jarrod Johnson 334ec00f3f Properly report client use of bad async id
Previously an expired async id would trigger unexpected error.  Now
it returns an error to client and avoids the trace log.
2019-01-08 15:43:41 -05:00
Jarrod Johnson 35380e5bac Add missing import
errno was erroneously omitted from previous commit
2018-12-12 10:15:33 -05:00
Jarrod Johnson 66471624bc Support caching SDR for pyghmi versions that support it
This will improve performance across confluent restarts for commands
like nodesensors, nodehealth, and nodeinventory.
2018-12-12 09:53:36 -05:00
Jarrod Johnson 8a03bc48de Tentatively store certutil
Commit to repository, even though not yet used.  It is likely to
be renamed.  The purpose is to help generate an appropriate self signed
cert for https including all the ip addresses as subject alternative
names so that names or addresses may be used with installers that
have had the cert injected.
2018-12-11 13:51:46 -05:00
Jarrod Johnson 5831be091a Auto-rescan on missed manual discovery
Same as in the bulk discover support.
2018-12-11 09:17:08 -05:00
Jarrod Johnson 8197c750bb Add batch support to nodeconfig 2018-12-10 09:47:49 -05:00
Jarrod Johnson a9f0312acd Add support for exporting only a mac csv
For the specific task of importing mac addresses but not
perturbing other xCAT configuration, provide output that can be used
with tabrestore.
2018-12-07 14:08:34 -05:00
Jarrod Johnson 21700e914a Add confluent2xcat command
Add command for exporting node data as an xCAT stanza file
2018-12-07 13:59:01 -05:00
Jarrod Johnson 5e15ae8e30 Update nodeconsole man page for tiling 2018-12-04 10:41:50 -05:00
Jarrod Johnson 5eef76f5d3 Try a more straightforward use of tiling
Rather than retiling for every node, defer tiling until the end.
This dramatically improves the startup time for a moderate number
of systems.
2018-12-03 15:57:08 -05:00
Jarrod Johnson df72bfa715 Merge branch 'master' of github.com:jjohnson42/confluent 2018-12-03 15:53:24 -05:00
Jarrod Johnson a6333459c4 Add tile option to nodeconsole
This allows nodeconsole to produce the 'tcons' behavior without
xCAT dependency.
2018-12-03 15:53:15 -05:00
Jarrod Johnson 075891bf74 Add option to confetty to help keep terminal open on early exit
For contexts where early execution execution almost always means
some sort of error, but the terminal automatically closes,
provide a minimum time to execute option so confetty will
forcibly slow things down in such a likely scenario.
2018-12-03 14:49:19 -05:00
Jarrod Johnson a937511354 Fix nodesetboot argument parsing 2018-11-30 16:09:47 -05:00
Jarrod Johnson 22503e7e11 Inject blank lines in ansible hosts file
This looks a bit more like a natural hosts file.
2018-11-29 15:21:37 -05:00
Jarrod Johnson 01d73308ed Pull back spurious blank lines 2018-11-29 15:04:56 -05:00
Jarrod Johnson cb16385ddb Add confluent2ansible
Utility that wil take a noderange and generate an appropriate
ansible hosts file, including carrying over pertinent groups.
2018-11-29 15:04:27 -05:00
Jarrod Johnson 853585f942 Have nodeattrib output be sorted
This make nodelist and nodeattrib output much easier to follow.
2018-11-29 10:02:37 -05:00
Jarrod Johnson 53996a1e9d Increase likelihood of IPMI results being sorted
Without incurring execution penalty, endeavor to sort available
data in an opportunistic way.  This certainly does not guarantee order,
but it makes it highly likely for quick queries to appear orderly.
2018-11-29 09:43:53 -05:00
Jarrod Johnson 558171124c Fix nodediscover man page formatting 2018-11-27 16:14:15 -05:00
Jarrod Johnson 05d028e9e9 Fix formatting of nodediscover man page
The list of fields could not be nicely nested in ronn,
give up but have hard line breaks as a compromise.
2018-11-27 15:36:36 -05:00
Jarrod Johnson b0a3bb18fe Add terminal resizing to http api
This enables javascript clients to submit terminal changes.
2018-11-27 09:12:53 -05:00
Jarrod Johnson 7207013abc Have httpapi be able to accept initial size on consoles
consoles and shells can now put into the body parameters including
the width and height.
2018-11-26 16:43:52 -05:00
Jarrod Johnson b511a02f20 Have correct size on connect for shell session
In addition to resize, also support initial size being set
2018-11-26 16:21:31 -05:00
Jarrod Johnson c60cb3a027 Implement resize from CLI client
The CLI resize is wired up for ssh usage.  At the time of this commit,
initial size is not handled.
2018-11-26 15:31:36 -05:00
Jarrod Johnson 9f137fa6d4 Begin work to send resize to remote
While we do not have a path forward for auto-resize in SOL consoles,
we can provide the capability for ssh consoles.  The CLI being enabled
is of course nice, but running ssh directly is still suggested in such
a context and ultimately the Web GUI will be the most prominent
consumer of the information.
2018-11-20 16:01:36 -05:00
Jarrod Johnson aa92898249 Have nodestorage create optionally read names from args
This is more symmetric with the way delete works.
2018-11-19 15:32:03 -05:00
Jarrod Johnson 2cb694b374 Update man page of nodediscover 2018-11-19 14:46:47 -05:00
Jarrod Johnson 24fd1e72e1 Expose advertised, not valided IPs in discovery
There are circumstances where the advertised IP is
useful information, even if that IP cannot be validated.

It is also the case that most of the time the advertised IP
is useless if not validated, so it is an optional field.
2018-11-19 14:39:56 -05:00
Jarrod Johnson 5b21a5b2c3 Fix spreadsheet support for the BMC gateway
The spreadsheet support used incorrect attribute name.
2018-11-19 09:50:04 -05:00
Jarrod Johnson c8ad94313e Provide useful error when trying to delete a volume that doesn't exist 2018-11-16 11:54:46 -05:00
Jarrod Johnson f71d51769b Provide clean print of created volumes
This presents the returned data in a manner consistent
with nodestorage show
2018-11-16 11:27:26 -05:00
Jarrod Johnson b5213e6972 Show data about created volumes upon volume completion.
Provide concrete feedback as to the results of the creation operation.
2018-11-16 11:19:27 -05:00
Jarrod Johnson 8d72f4d64a Fix volume name creation
The volume names were not being honored, fix passing the arguments.
2018-11-15 16:25:03 -05:00
Jarrod Johnson fcd46c7b72 Provide cleaner output for nodestorage delete
Rather than dumping the structure of the response, provide a consistent
plain text output.
2018-11-15 16:18:24 -05:00
Jarrod Johnson 6efb8ff1b7 Add globbing protection to nodestorage command
This mitigates risk of mistargeting a nodestorage command due to
unfortunate bash glob match.
2018-11-15 16:15:01 -05:00
Jarrod Johnson c227c2353b Provide better error on nodediscover assign
Rather than the rather useless unexpected error, actually
describe specific cases of wrong username or password.
2018-11-15 13:41:48 -05:00
Jarrod Johnson cb2133e871 Change strategy for pam.d entry
The symbolic link did not stay a symbolic link.
Use %post in rpm instead.
2018-11-14 15:11:05 -05:00
Jarrod Johnson c56c1948a9 Add confluent pam to packaging
This enables PAM passwords to work by default,
rather than requiring user to perform more
configuration.
2018-11-14 14:55:26 -05:00
Jarrod Johnson 34b30a1bd8 Rework password authentication
Have the cache operate against the sha256 of the passphrase rather
than the passhprase directly (mitigate presence of password in memory).

Pull PAM into the cache behavior to accelerate PAM based usage.

Rearrange things so that both built in confluent and PAM passwords
can be used.
2018-11-14 14:52:03 -05:00
Jarrod Johnson 0e7bfe4f40 Use scanning status to control rescan behaviors
This causes the manual assignment to sleep less and for the rescan
command to meaningfully slow down shell requests to provide better sense
of when scan completes.
2018-11-14 14:17:12 -05:00
Jarrod Johnson a93a759b72 Make /networking/macs data available through nodediscover
This will help combine the data together more easily.
2018-11-14 14:11:03 -05:00
Jarrod Johnson cba514692c Bring the XCC check fix to IMM
The same check that works for XCC should be applied to IMM
2018-11-13 16:17:39 -05:00
Jarrod Johnson 2bb0a70a24 Provide an xid if one is not preserved
The SLP xid may be gone in a recheck, default to 42 in such a case.
2018-11-13 16:09:37 -05:00
Jarrod Johnson 1b84cd43fe Fix the auto-healing support
There was a mismatch between the handlers signature and expectation by
the discovery core.
2018-11-13 15:55:24 -05:00
Jarrod Johnson 39839a9f2a Add auto-healing of incomplete SLP data
If a device handler indicates an SLP data as incomplete, schedule a
attempt to fixup that specific one.
2018-11-13 15:37:41 -05:00
Jarrod Johnson 8473cb1cf8 Survive SLP values with =
If the slp parsing produces = in the value, ignore it and do best
effort to get the viable data out.
2018-11-09 15:38:40 -05:00
Jarrod Johnson 1a10b5d747 Have confluent2lxca use current config for address
In a confluent2lxca scenario, it is highly probably that confluent's
attribute is not viable for LXCA usage (link local address).

Give the current configuration the opportunity to replace the
confluent reference with the current IPv4 of the host.
2018-11-09 08:53:10 -05:00
Jarrod Johnson 82a7012527 Add a command to generate xClarity Administrator import
This will generate a bulk import file for use with the xClarity
Administrator appliance.
2018-11-09 08:33:04 -05:00
Jarrod Johnson 199a948b33 Fix ordering without custom field list
The order argument only had any meaning when used in custom fields.
Add a loop in the custom field agnostic section of the code to correct
the behavior.
2018-11-09 08:32:28 -05:00
Jarrod Johnson 6fc305d6a0 Add ordering by field to nodediscover list
This provides single column sort for more managable listing of
nodediscover items.
2018-11-06 16:34:22 -05:00
Jarrod Johnson 75b6221dcf Allow requesting custom columns
This allows for more data to be presented and some useless data
to be pruned.
2018-11-06 15:52:20 -05:00
Jarrod Johnson bd5032268e Fix csv output mode of nodediscover list
The changes made for tabulator broke csv output, fix that back.
2018-11-06 15:33:04 -05:00
Jarrod Johnson 0aa0289b06 Clean out dead code
There is some dead and commented code to be cleaned out.
2018-11-06 15:30:18 -05:00
Jarrod Johnson 96df7871cb Convert nodediscover to use Tabulator
This opens the path to more customized output and have the appropriate
formatting.  Also revise the Tabulator code to more closely match
the original nodediscover list output.
2018-11-06 15:28:27 -05:00
Jarrod Johnson 82ee69b56c Age out macmap on node database changes
This mitigates problems where automation fails to quickly
react to changes/fixes in the net attributes.
2018-11-06 08:18:37 -05:00
Jarrod Johnson 37899ad39e Do not inject 'None' into builddesc
If such data came from remote system, do not cause a stack trace.
2018-11-05 10:43:36 -05:00
Jarrod Johnson 43fb4467b7 Add error if chain goes off into non-existent nodes
Various behaviors break if the administrator declares a chain goes
to nowhere, throw up an error and hopefully see it caught to detect
this misconfiguration.
2018-11-02 15:56:34 -04:00
Jarrod Johnson f5f9403eff Fix incorrect variable name in nodediscover
The field name was incorrectly referencing the last field
rather than the current.
2018-11-02 15:50:02 -04:00
Jarrod Johnson 78e7381442 Add implicit rescan on unmatched csv data
If the csv file contains criteria we can't match, implicitly
try a rescan automatically to try to catch it.
2018-11-02 15:18:55 -04:00
Jarrod Johnson 005cefc914 Add volume creation and deletion to nodestorage 2018-11-01 16:59:42 -04:00
Jarrod Johnson 5f38cce51e Finish nodestorage show
It now shows the pertinent details of storage on a node.
2018-11-01 10:43:28 -04:00
Jarrod Johnson 5d358eaeb0 Switch to output format more like nodeinventory
Other confluent commands (apart from nodediscovery) set a particular
convention.  Go by that convention (at least by default)
2018-10-30 16:28:59 -04:00
Jarrod Johnson 115a6e9dd1 Add helper for tabular output
Provide a quick class for auto-sizing tabular output.
2018-10-30 16:23:34 -04:00
Jarrod Johnson a034d05cc8 Draft tabular output of disk information
Print out roughly the data that will be desired in the storage show.
2018-10-30 16:10:37 -04:00
Jarrod Johnson 6378f823f3 Add resource name to the storage messages
The storage messages need to have the references preserved
for CLI consumption.
2018-10-30 15:46:54 -04:00
Jarrod Johnson 079dfed11e Add type to storage messages
Storage messages are likely to be grouped together and need
more to disambiguate them.
2018-10-30 15:28:03 -04:00
Jarrod Johnson d836bf7298 Map health to nagios compatible codes
nodehealth adds granularity and health to the return code.
Rather than only reflecting failure running command, also
have nodehealth assign exit code according to the expectations
of nagios.
2018-10-30 13:56:09 -04:00
Jarrod Johnson 25b969a4db Add 'all' element to configuration/storage
Provide a way to provide all the data about storage configuration
in a single call.
2018-10-30 10:25:41 -04:00
Jarrod Johnson 950abde20e Remove 'all' from storage subelements
This concept is potentially problematic, as a volume named 'all' is
valid.  Additionally, if really wanting all, the caller probably wants
the full storage configuration, better provide that up a level to
avoid requiring many calls to do that.
2018-10-30 10:05:48 -04:00
Jarrod Johnson 37be696f23 Merge branch 'master' of github.com:jjohnson42/confluent 2018-10-29 14:56:37 -04:00
Jarrod Johnson 73cab3774d Add support for volume creation 2018-10-26 14:31:28 -04:00
Jarrod Johnson c2d52d4f83 Add functionality to delete volumes
Further enriching the storage api by adding the ability to delete
a volume.
2018-10-25 16:31:32 -04:00
Jarrod Johnson fd17559a73 Show result of changing disk state.
When changing disk state, let the caller know the result explicitly.
2018-10-25 16:11:54 -04:00
Jarrod Johnson 3945ccd5c3 Advance storage configuration API
Enumerate disks in an array in disks list.

Add array associated with disk to disk data.

Show detailed data on arrays and volumes.
2018-10-25 16:07:07 -04:00
Jarrod Johnson 7c006b33bc Implement functionality to configure disks
Disks may now have their state changed between hotspare, unconfigured,
and jbod.
2018-10-25 14:48:58 -04:00
Jarrod Johnson c96b5f0270 Fix spurious trace on immediate exit confetty
When confetty exits without doing anything, it causes
sockapi to reference an empty request.  Check for that before
checking if it is a collective request.
2018-10-25 14:12:15 -04:00
Jarrod Johnson 7e72240d98 Add protection against duplicate import data
nodediscover assign from csv will now guard against human error
in putting the same data in multiple times.
2018-10-25 11:07:56 -04:00
Jarrod Johnson c150a848fd Normalize drive state
Since drive state is a key api feature, make sure it is normalized
to a set vocabulary.
2018-10-24 16:36:38 -04:00
Jarrod Johnson bc7a197a8c Merge branch '18csi' 2018-10-23 09:16:32 -04:00
Jarrod Johnson 6973736c6a Set password before setting username
The BMC is at much higher risk for rejecting the password
(e.g. the password does not pass complexity requirements).  If the
username changes, but the password is still default, it is very
confusing.  Give the password change the chance to break the
configuration process first.
2018-10-23 09:16:15 -04:00
Jarrod Johnson d70c3dcad7 Merge branch '18csi' 2018-10-23 09:10:01 -04:00
Jarrod Johnson f9055a258e Provide specific completion behavior for noderun/nodeshell 2018-10-23 09:09:03 -04:00
Jarrod Johnson 76a96fa054 Merge branch '18csi' 2018-10-18 15:44:13 -04:00
Jarrod Johnson c784a4ec9b Fix noderun output of continuing commands
noderun always only output at the end, fix the
mistake in the select statement.
2018-10-18 15:43:57 -04:00
Jarrod Johnson 2ff47b886d Fix noderun output of continuing commands
noderun always only output at the end, fix the
mistake in the select statement.
2018-10-18 15:43:36 -04:00
Jarrod Johnson 51037e2487 Change 'status' to 'state'
This is more consistent with several other confluent messages.
2018-10-17 09:37:31 -04:00
Jarrod Johnson 614b916ca4 Merge branch '18csi' 2018-10-16 09:39:00 -04:00
Jarrod Johnson 4077346d30 Rename api from drives to disks
It just feels more appropriate to use disks rather than drives.
2018-10-16 09:00:25 -04:00
Jarrod Johnson 8a4bf22a7e Further flesh out the storage api support
Add ability to list arrays and volumes.
2018-10-15 16:27:12 -04:00
Jarrod Johnson f2dd501de9 Do not proceed to try to upload if file doesn't exist
After relaying the error, it went ahead and
attempted the update, contrary to any reasonable expectation.
2018-10-15 11:15:13 -04:00
Jarrod Johnson f835057ae4 Do not proceed to try to upload if file doesn't exist
After relaying the error, it went ahead and
attempted the update, contrary to any reasonable expectation.
2018-10-15 11:14:59 -04:00
Jarrod Johnson 48913218a6 Merge branch 'master' of github.com:jjohnson42/confluent 2018-10-12 15:47:44 -04:00
Jarrod Johnson a11e4b71ce Merge branch '18csi' 2018-10-12 15:47:38 -04:00
Jarrod Johnson e9ba49a4aa Intercept another 'unexpected error'
During a particularly hectic init, Invalid Session ID
may occur if a command is ran particularly early.  Intercept
and replace a more clean message.
2018-10-12 15:46:54 -04:00
Jarrod Johnson deb90fbca9 Fix trace on early console connect
If the trace happens before tracelog is ready, just print the output
to the stdout log for now.
2018-10-12 14:56:54 -04:00
Jarrod Johnson 8cae5ea101 Fix trace on early console connect
If the trace happens before tracelog is ready, just print the output
to the stdout log for now.
2018-10-12 14:28:21 -04:00
Jarrod Johnson f830658818 Merge branch '18csi' 2018-10-12 13:33:09 -04:00
Jarrod Johnson 3105b9b1f9 Significantly rework the collective startup behavior
One, make the tracking bools enforce a lock to reduce confusion

Treat an initializing peer as failed, to avoid getting too fixated
on an uncertain target.

Make sure that no more than one follower is tried at a time by
killing before starting a new one, and syncing up the configmanager
state

Decline to act on an assimilation request if we are trying to connect
and also if the current leader asks us to connect and we already are.

Avoid calling get_leader while connecting, as that can cause a member
to decide to become a leader while trying to connect, by swapping
the reactions to the connect request.

Avoid trying to assimilate existing followers.

Fix some logging.
2018-10-12 11:45:23 -04:00
Jarrod Johnson f525c25ba6 Provide more verbose collective logging
This helps understand the flow in practice of collective behavior.
2018-10-11 15:15:11 -04:00
Jarrod Johnson 3012de1fe4 Prioritize deletion of transactioncount
If the invalidation is incomplete, make sure that transactioncount
is invalidated first to avoid it being able to propogate through
a collective.
2018-10-11 09:16:57 -04:00
Jarrod Johnson be930fc076 Add missing subsystem marker from a collective log 2018-10-10 16:30:28 -04:00
Jarrod Johnson 2d0199a4e9 Wrap bdb deletion in same lock that sync itself uses
If os.remove happens at a bad time, it causes an unfortunate behavior
in dbm.  Serialize this sort of operation to avoid the bad behavior.
2018-10-10 15:24:55 -04:00
Jarrod Johnson 6b70a4322a Fix rollback
The fix for the stale data introduced breaking clear rollback
Restore the behavior and make self._cfgstore a somewhat slower property
for now.
2018-10-10 15:22:20 -04:00
Jarrod Johnson 6a784e3a1c Ensure sync is complete prior to leaving configmanager sync
The initialization lock is meant to avoid collective and generic
initialization stepping on each other.  This is somewhat reduced in
efficacy if one has a sync running while the other is changing relevant
data.
2018-10-10 14:49:33 -04:00
Jarrod Johnson 3b2b96a4cf Force fullsync if dead sync thread likely
If the sync thread died previously, force the next sync to be full.
2018-10-10 14:32:13 -04:00
Jarrod Johnson 32ddb33de3 Fix error when trying to do fullsync without globals yet
If globals is missing, then do not break the sync trying to handle it
2018-10-10 13:11:15 -04:00
Jarrod Johnson b77ed8dbff Fix config sync on dead writer
The sync thread can die without clearing syncrunning.  Make sure that
the thread is alive *and* that the thread has not indicated
intent to give up.
2018-10-10 13:07:27 -04:00
Jarrod Johnson d5c093a30d Provide fallback for unexpected reply in collective show 2018-10-10 09:46:01 -04:00
Jarrod Johnson cf9d2a43e8 Revert "Provide fallback for unexpected reply in collective show"
This reverts commit 2f566fb81d.
2018-10-10 09:44:06 -04:00
Jarrod Johnson 2f566fb81d Provide fallback for unexpected reply in collective show 2018-10-10 09:41:25 -04:00
Jarrod Johnson 92a3b02dc5 Merge branch '18csi' 2018-10-10 09:24:18 -04:00
Jarrod Johnson 94c8cf3ff2 Apply the correct change to collate 2018-10-10 09:24:01 -04:00
Jarrod Johnson 049897fc15 Merge branch '18csi' 2018-10-10 09:21:07 -04:00
Jarrod Johnson 8741a27c24 Merge branch '18csi' of github.com:jjohnson42/confluent into 18csi 2018-10-10 09:09:12 -04:00
Jarrod Johnson 1c494fc4fc Correct mistake in the collate log support 2018-10-10 09:08:45 -04:00
Jarrod Johnson 1ee418392f Provide better error behavior on missing collective.manager
collective.manager was a blanket response, make it per node and
only triggered by the bad nodes, not the rest.
2018-10-09 15:44:17 -04:00
Jarrod Johnson 2a7eeb6e08 Fix missing argument in calling a function 2018-10-09 15:21:11 -04:00
Jarrod Johnson 5c83c78a90 Add warning on incompatible ssh key with SLES12 2018-10-09 14:44:06 -04:00
Jarrod Johnson 6a466b0100 Avoid proxy consoles generating proxy consoles
When the client is a proxy term, disable ability to produce
proxy terminals.  This was wreaking havoc with client
count with ghosts and triggering output multiplication.
2018-10-09 13:21:02 -04:00
Jarrod Johnson 67b93ee6b0 Merge branch '18csi' 2018-10-09 09:46:44 -04:00
Jarrod Johnson 6b4a21d613 Add log option to collate for per node logs 2018-10-09 09:37:25 -04:00
Jarrod Johnson 5f46899358 Prevent clear_configuration from invaliding existing ConfigManager
Clear out the existing dictionary instead of replacing it.

This prevents configmanager objects from being stuck.
2018-10-08 16:51:58 -04:00
Jarrod Johnson a3bc17b465 Merge branch '18csi' 2018-10-08 15:56:43 -04:00
Jarrod Johnson 20a37f8db5 Add mention of the -u options to the manpages. 2018-10-08 11:02:33 -04:00
Jarrod Johnson c6b8aaf372 Fix mistake in the nodegroupdefine man page 2018-10-08 10:57:48 -04:00
Jarrod Johnson 5baab5bef4 Add more stateful to completion
Allow it to sense words already used in command.  Refactor to common
code for similar ones.
2018-10-08 10:47:38 -04:00
Jarrod Johnson 73c06fd25e Fix display of error on join of collective 2018-10-08 09:54:03 -04:00
Jarrod Johnson 8d9a082739 Provide better exceptions and propogate them to client on snmp
When doing snmp, messages would always go to log only, even if the
user was at the confetty cli.  Give user access to knowing the error
impacting the query.
2018-10-04 14:59:25 -04:00
Jarrod Johnson 32602fbba3 Provide interactive handling of key mismatch in ssh sessions
Before, ssh would close without so much as a warning, fix this by
dealing with the key data.
2018-10-04 10:23:55 -04:00
Jarrod Johnson 2f616d4586 Better error when collective.manager is set to something invalid
If the collective.manager field does not correspond to any collective
manager, give a useful error rather than unexpected error.
2018-10-03 16:23:20 -04:00
Jarrod Johnson 15dc4937ee Add hyphen options to various completion 2018-10-02 14:44:25 -04:00
Jarrod Johnson 10cb1b77dd Extend the nodeboot man page 2018-10-02 14:36:07 -04:00
Jarrod Johnson d86e1fc4eb Give the cfg init a lock
Move collective manager and configmanager to share a configinitlock,
so that bad timings during internal initialization and collective
activity cannot interfere and produce corrupt database.

This became an issue with the fix for 'everything' disappearing.
2018-10-02 10:17:44 -04:00
Jarrod Johnson 29fcd59f8b Fix usage of check_quorum()
It is not a boolean, it is exception driven.
2018-10-01 16:02:45 -04:00
Jarrod Johnson 78a1741e0e Fix usage of check_quorum()
It is not a boolean, it is exception driven.
2018-10-01 16:02:16 -04:00
Jarrod Johnson 4329c1d388 Have collective start bail out if leader
Leader should not relinquish if quorum, so don't bother in such
a case.
2018-10-01 15:50:49 -04:00
Jarrod Johnson c13ebe36ae Have collective start bail out if leader
Leader should not relinquish if quorum, so don't bother in such
a case.
2018-10-01 15:50:31 -04:00
Jarrod Johnson 9495a41f85 Cancel retry if we become leader
If an instance is first to start, it's retry should be canceled
when other members prod it to become leader.
2018-10-01 15:29:42 -04:00
Jarrod Johnson b0b5493ff7 Cancel retry if we become leader
If an instance is first to start, it's retry should be canceled
when other members prod it to become leader.
2018-10-01 15:29:18 -04:00
Jarrod Johnson 484435c732 Fix /networking/macs/by-mac
The module apimacmap was not correctly scoped.
2018-10-01 14:40:25 -04:00
Jarrod Johnson 326f56219b Fix /networking/macs/by-mac
The module apimacmap was not correctly scoped.
2018-10-01 14:40:02 -04:00
Jarrod Johnson e098c0ba91 Fix missing tenant argument on user management function
The tenant was omitted preventing those particular rpc calls from
working correctly.
2018-10-01 14:04:03 -04:00
Jarrod Johnson a5d5f4a6a4 Fix missing tenant argument on user management function
The tenant was omitted preventing those particular rpc calls from
working correctly.
2018-10-01 14:03:45 -04:00
Jarrod Johnson 61e7c90ad1 Do not restart on intentional kill
Additionally, add some output to help filter events log
2018-10-01 10:32:55 -04:00
Jarrod Johnson 51194b275b Do not restart on intentional kill
Additionally, add some output to help filter events log
2018-10-01 09:35:02 -04:00
Jarrod Johnson e57cdf9a7b Add more collective event log handling
More detail to analyze how the collective membership is handled.
2018-09-27 15:15:05 -04:00
Jarrod Johnson e634817b34 Add more collective event log handling
More detail to analyze how the collective membership is handled.
2018-09-27 15:14:45 -04:00
Jarrod Johnson 10ce7a9de9 Add more logging to collective process 2018-09-27 10:51:06 -04:00
Jarrod Johnson 0724ad812b Add logging to the assimilation phase of collective
When attempting assimilation, provide logging about the attempt.
2018-09-27 10:51:01 -04:00
Jarrod Johnson a3b0b0240d Abort assimilation attempt on non-member cleanly
If a confluent instance has forgotten the collective, more cleanly
handle the situation, and abort the assimilation rather than assuming
the peer should be leader, unless txcount specifically is called out
as the reason.
2018-09-27 10:50:54 -04:00
Jarrod Johnson 7f06c69d3c Add more logging to collective process 2018-09-27 10:49:57 -04:00
Jarrod Johnson b5af770f21 Add logging to the assimilation phase of collective
When attempting assimilation, provide logging about the attempt.
2018-09-27 10:38:00 -04:00
Jarrod Johnson 247650868e Abort assimilation attempt on non-member cleanly
If a confluent instance has forgotten the collective, more cleanly
handle the situation, and abort the assimilation rather than assuming
the peer should be leader, unless txcount specifically is called out
as the reason.
2018-09-27 10:30:30 -04:00
Jarrod Johnson 9e8b2dd973 Begin storage configuration support
Start by adding a storage oriented configuration area, and have it be
able to list and show detail on disks.
2018-09-26 15:29:29 -04:00
Jarrod Johnson 99fdb20f87 Add nodemedia specific completion 2018-09-21 14:22:46 -04:00
Jarrod Johnson 60bb4c89fb Add specific completions for nodeboot and nodesetboot 2018-09-21 14:09:49 -04:00
Jarrod Johnson 5d52fd2fc1 Add nodeidentify specific completion
Additionally refactor common code into a function
2018-09-21 13:54:43 -04:00
Jarrod Johnson 18bebde337 Disable gssapi in paramiko
It is just plain broken, workaround by tanking calls to gssapi prior
to pulling in paramiko.
2018-09-21 13:46:07 -04:00
Jarrod Johnson c68c4d8cf7 Fix the 'list' subcommand of nodefirmware
nodefirmware did not properly set up if 'list' was given
2018-09-21 10:41:15 -04:00
Jarrod Johnson 1de84f0417 Add missing nodesupport man page 2018-09-21 09:57:34 -04:00
Jarrod Johnson 44bf2872b7 Provide more tailored completion for some commands
Additionally, modify the nodefirmware command to have a `list`
subcommand, so that tab completion doesn't aggressively send
someone to update.
2018-09-21 09:57:17 -04:00
Jarrod Johnson c209010126 Add tab completion for bash
For interactive bash use, have some completions
2018-09-20 16:02:45 -04:00
Jarrod Johnson 21b4a2f6f3 Merge branch 'master' of github.com:jjohnson42/confluent 2018-09-20 11:05:24 -04:00
Jarrod Johnson 36fc23d692 Avoid VT control codes on exit through pipe
Piped commands were subjected to terminal control sequences that
could interfere with desired operation.
2018-09-20 11:05:00 -04:00
Jarrod Johnson f601032a66 Fix everything group missing if nodegroup created before node
everything group was not making it to disk unless a node is created
first.  Correctly mark the need for disk sync to fix.
2018-09-14 16:50:20 -04:00
Jarrod Johnson 7c550bd68e Fix prefix fixup
It was not allowing same label across nodes.
2018-09-10 15:09:50 -04:00
Jarrod Johnson db5f861dc5 Fix introduced typo in error message 2018-09-10 14:25:04 -04:00
Jarrod Johnson d04be19ae5 Preferentially use a 'name' subfield as 'name'
Pyghmi now may suggest a more useful name.  The component name
is unique, but 'name' can indicate the common name of things with
multiple instances.
2018-09-07 14:37:02 -04:00
Jarrod Johnson 07532e2a3f Have nodeinventory disambiguate duplicate labels.
The data is still there for putting identical cards together, but
the prefix is unique, particularly important for json mode.
2018-09-07 11:49:13 -04:00
Jarrod Johnson e7be24d478 Revert "Fix non-unique name for similar inventory items."
This reverts commit 47a53a51e4.
2018-09-07 11:44:01 -04:00
Jarrod Johnson 34b7abcb2d Change systemd unit to not have PIDFile
systemctl restart *always* prints a worrying message
with pidfile.
2018-09-07 11:27:43 -04:00
Jarrod Johnson 47a53a51e4 Fix non-unique name for similar inventory items. 2018-09-07 11:16:09 -04:00
Jarrod Johnson abc15974da Merge branch 'master' of github.com:jjohnson42/confluent 2018-09-07 11:11:26 -04:00
Jarrod Johnson b3bf6929df Add replacement logic for another generic variant
In IMM, PCeGen3 x8 and similar is also possible.
2018-09-06 16:16:26 -04:00
Jarrod Johnson 2a8d61ecf6 Enrich the less than useful 'Adapter' inventory items
We can provide DNS provided info about such generic items to
make them look more fleshed out.
2018-09-06 16:10:48 -04:00
Jarrod Johnson cf3e9037ab Provide 'discovery.passwordrules'
This provides an ability to designate the desired rules that
are applied in the wake of automatic discovery.  The most popular
would be 'expiry=no,loginfailures=0'
2018-09-05 15:50:36 -04:00
Jarrod Johnson 03135543a6 Add 'switchuser' and 'switchpass' aliases 2018-09-05 13:51:19 -04:00
Jarrod Johnson 38228ebc9b Fix the prompting code changes 2018-09-04 11:09:26 -04:00
Jarrod Johnson d6110c7118 Add -p to nodegroupattrib
Also modify the man pages to reflect the updates.
2018-09-04 09:56:51 -04:00
Jarrod Johnson f92b1ed4a3 Implement ability to prompt for nodeattrib options.
For certain attributes, notably passwords, it is sometimes desirable
to prompt interactively to help facilitate keeping such data out of
bash_history, screen sharing, and ps output.  -e enables this if the
user is aware of how to use 'read', -p is a quicker way to enable this.
2018-09-04 09:38:01 -04:00
Jarrod Johnson 368087fb51 Have nodeattrib and nodeconfig accept wildcard to select values 2018-08-30 10:14:03 -04:00
Jarrod Johnson 46d62e67de Do not include advanced in comparedefault by default
Advanced settings may do unusual things, only check if explicitly
requested to do so.
2018-08-30 09:58:15 -04:00
Jarrod Johnson 118d1aec0d Allow nodeboot to harmlessly take -u
It doesn't actually change behavior, but request for compatibility
is being honored.
2018-08-30 09:39:20 -04:00
Jarrod Johnson 7c9089c87d Change nodeconfig -r to take a parameter
This opens up for future ability to control the restore to default.
2018-08-30 09:35:16 -04:00
Jarrod Johnson ba18b9936f Fix mistakes in previous commit 2018-08-29 15:15:34 -04:00
Jarrod Johnson 3b7ecd0095 Add ability to clear system configuration
This provides a method to request the system firmware be restored to
factory defaults.
2018-08-29 14:49:19 -04:00
Jarrod Johnson 19e9583b47 Fix formatting on node*define man page sources 2018-08-28 15:08:03 -04:00
Jarrod Johnson 8352007570 Limit to one active scan at a time
Additionally, provide read access to rescan for discovery.
2018-08-28 11:25:48 -04:00
Jarrod Johnson f7965d235a Improve /networking/macs API behavior
For the 'by-mac', only remove the structure when it is ready for API
view without changing internal view.

For the 'by-switch', do the update per switch and after it's done.

Provide ability to check scan status through reading
/networking/macs/rescan
2018-08-28 11:10:32 -04:00
Jarrod Johnson 6aec9534e7 Fixes for nodesupport 2018-08-23 16:56:40 -04:00
Jarrod Johnson 3ee6334db2 Fix transfer owner argument for servicedata 2018-08-23 16:48:10 -04:00
Jarrod Johnson 582a4de62d Add CLI and directory support for nodesupport 2018-08-23 16:36:41 -04:00
Jarrod Johnson c9959d4082 More of the service data retrieval api
More progress is made toward the goal
2018-08-23 16:14:49 -04:00
Jarrod Johnson fa11fb54cb Add API support for getting service data
Service data retrieval is a common activity required
for interacting with support.
2018-08-23 15:39:25 -04:00
Jarrod Johnson ee3b824870 Add /description to nodes api 2018-08-23 08:44:41 -04:00
Jarrod Johnson 55f5b30369 Merge branch '21' 2018-08-22 16:29:58 -04:00
Jarrod Johnson 784e4bed2f Force cleanup if follow thread dies of exception
If something killed a follow thread, it was not always able to fire the
recovery off.  Wrap the risky code in a try statement.
2018-08-20 15:02:34 -04:00
Jarrod Johnson df7cba00fd Amend the message on collective failure 2018-08-17 16:45:45 -04:00
Jarrod Johnson dfb720d0ee Have collective command warn if the libssl library is not viable
Main example is RedHat providing pyOpenSSL of relatively ancient
vintage.
2018-08-17 13:57:13 -04:00
Jarrod Johnson f5d5cbd67b Have collective command warn if the libssl library is not viable
Main example is RedHat providing pyOpenSSL of relatively ancient
vintage.
2018-08-17 13:56:38 -04:00
Jarrod Johnson 319fec2145 Add advanced to nodeconfig 2018-08-17 11:16:11 -04:00
Jarrod Johnson 8787d23b3a Add advanced to API for system configuration.
pyghmi makes hiding optional advanced settings.
2018-08-17 10:59:50 -04:00
Jarrod Johnson 9b48110155 Do not proceed a logged, but broken session
It shouldn't be possible for this to be the case, but out of an
abundance of caution, check for this.  So far only produced this by
forcing broken = True in a debug session.  Intended to catch an alleged
scenario where console was managing to use a broken session (fixed in
pyghmi) and have confluent also recognize the situation for non-console
usage).
2018-08-16 14:43:16 -04:00
Jarrod Johnson 3064e7bef6 Ensure path is made prior to creating transactioncount
Fresh install will be missing /etc/confluent/cfg.  Advance the
_mkpath call to fix this problem.
2018-08-08 18:05:45 -04:00
Jarrod Johnson 1d4df8af3a Fix extraneous error in log on connectivity loss 2018-08-07 15:43:53 -04:00
Jarrod Johnson 2aba6e469c Correct variable name in the 'connected' fix 2018-08-07 15:31:41 -04:00
Jarrod Johnson de58593f14 Fix inability to notice underlying broken layers of the SOL
Through an unknown set of circumstances, an solconnection could be
stuck 'connecting'.  In every case analyzed, the ipmi_session was
broken.  Use that to detect a class of failure and react appropriately.
2018-08-07 15:12:53 -04:00
Jarrod Johnson ecbe1a86b1 Revert "Have nodeconsole restore term on exit"
This reverts commit 2972374da8.
2018-08-02 10:27:37 -04:00
Jarrod Johnson 2972374da8 Have nodeconsole restore term on exit 2018-08-02 10:07:41 -04:00
Jarrod Johnson 81dd6202d3 Fix when rpc has no 'exc' but has 'xid' 2018-07-30 11:26:09 -04:00
Jarrod Johnson 36a202842a Fix collective on rpc exception
Exceptions on collective calls were not correctly handled, fix
the handling so that collective continues and also the calling function
is correctly given the exception.
2018-07-30 09:33:24 -04:00
Jarrod Johnson 6a8e24dd0e Prioritize interactive feedback part of console handling. 2018-07-26 08:55:25 -04:00
Jarrod Johnson d3afeb3414 Fix web shell if user hits enter too fast 2018-07-24 17:20:22 -04:00
Jarrod Johnson 1bf4c0ac0a Have collective coalesce watched updates
Particularly chatty output can make collate be unreasonable in
low quality terminals and links.  Throttle to about 4 times a second.
2018-07-24 16:50:46 -04:00
Jarrod Johnson 8e422ef822 Fix ssh access
Fixed handler (e.g. ssh) did not return console consistent with
the plugin defined handlers.
2018-07-24 16:48:46 -04:00
Jarrod Johnson f0edbbad39 Have collective show present some info when not in quorum 2018-07-20 14:11:38 -04:00
Jarrod Johnson 5cf1671350 Make the takeover process more deterministic
Try to avoid submitting to be a follower while we are currently
becoming a leader
2018-07-20 13:50:42 -04:00
Jarrod Johnson e5c4219ee9 Reorder certificate check
First order of business is to verify certificate before even thinking
about if the request is possible
2018-07-20 13:34:14 -04:00
Jarrod Johnson 3ff7e42074 Change behavior for fallback handling
Fallback would do nothing to fix a persistent problem with an IPMI
session.  For lack of knowing how to avoid the situation, at least
make changes so it won't go wrong in the future.
2018-07-20 13:20:50 -04:00
Jarrod Johnson fab177e077 Fix node[group][attrib|define] handling of =
Attributes with = in the value were not handled correctly,
fix by only doing one split.
2018-07-20 09:54:17 -04:00
Jarrod Johnson a1ba5f59a8 Fix collective show on non-collective 2018-07-19 17:21:01 -04:00
Jarrod Johnson 9bcca6bfad Provide collective show on all members 2018-07-19 17:08:20 -04:00
Jarrod Johnson 96671ace4e Correct collective show behavior 2018-07-19 16:48:30 -04:00
Jarrod Johnson bcff3fc962 Improve collective show readability 2018-07-19 16:39:13 -04:00
Jarrod Johnson 54d93571d1 Have leader provide more data in collective show 2018-07-19 16:26:05 -04:00
Jarrod Johnson f2f902de7b Have collective show report when collective inactive
Collective show was misleading if not in a collective.
2018-07-19 15:59:15 -04:00
Jarrod Johnson a09792f969 Schedule periodic attempts to restart collective
If collective is lost due to connectivity, this will cause
occasional attempts to bring it back.
2018-07-19 15:49:05 -04:00
Jarrod Johnson 7d16c943a8 Handle updating address of collective member on connect
If a collective member changes its IP address, update at the next
possible opportunity.
2018-07-19 15:24:08 -04:00
Jarrod Johnson b053d41cd8 Error on loss of manager in flight 2018-07-19 14:36:23 -04:00
Jarrod Johnson 200569e7af Merge branch 'master' into clustertime 2018-07-19 13:32:00 -04:00
Jarrod Johnson c3c0e1570a Push quorum state to followers
The followers need to know quorum state.
2018-07-19 13:27:21 -04:00
Jarrod Johnson 10c82a72b5 Restore message on unreachable collective member
The parallel execution had broken how that message transmits.

Bonus, make it a per node error.
2018-07-18 16:49:54 -04:00
Jarrod Johnson 79cdf65a72 Fix SLES sockapi
Previous fix was applied to the incorrect section of code
2018-07-18 15:07:22 -04:00
Jarrod Johnson 497ca40492 Do not abort connecting process on bad cert
The target may be non-viable, but don't let that ruin the party
for everyone.  Let it keep going as if the system were down.
2018-07-18 14:58:16 -04:00
Jarrod Johnson fd33e6ae01 Fix non-collective confluent mode
list_collective returns an iterator, which will be True...
2018-07-18 14:53:23 -04:00
Jarrod Johnson 32f944e67c Handle unclean loss of current proxy host
If transition is less than gentle, provide a path to restore automatic
if it gets moved.
2018-07-18 14:32:39 -04:00
Jarrod Johnson dcad9f5a75 Add keepalive and acks to collective
Detect unplugged condition (eventually).
2018-07-18 13:45:03 -04:00
Jarrod Johnson 2a34388d09 Add -p to man page for nodepower 2018-07-18 11:02:12 -04:00
Jarrod Johnson 6993e0b496 Fix nodepower argument parsing
nodepower was assuming that the second parameter was always the
state regardless of option parsing.  Use args instead to fix.
2018-07-18 11:00:01 -04:00
Jarrod Johnson b7fe72673d Add clear node/group attributes to collective
collective was not syncing clear directives.
2018-07-17 15:57:48 -04:00
Jarrod Johnson 0159bf1b1d Fix typo in error message 2018-07-17 15:39:08 -04:00
Jarrod Johnson cf9ad11290 Short out operations if in collective mode but no collective.manager 2018-07-17 15:25:12 -04:00
Jarrod Johnson ddd7ef5eba Fix proxyconsole break and reopen 2018-07-17 15:05:09 -04:00
Jarrod Johnson 73da8ec8b5 Fix ProxyConsole if self.remote is not yet set 2018-07-17 14:44:59 -04:00
Jarrod Johnson eac4d97732 Disengage remote console on manager change
This results in a more direct treatment of manager change.
2018-07-17 13:10:01 -04:00
Jarrod Johnson fa9ecfbb94 Merge branch 'clustertime' of github.com:jjohnson42/confluent into clustertime 2018-07-17 11:46:53 -04:00
Jarrod Johnson fc5472065a Catch missing '@' in token as invalid token 2018-07-17 11:46:40 -04:00
Jarrod Johnson cb0845596e Provide explanation about nodemedia list and no media. 2018-07-17 11:20:27 -04:00
Jarrod Johnson 0d936e0059 Ensure no more than one in-flight slave connection from a given follower
This will prevent a connection from deregistering itself after the
replacement registers itself.
2018-07-17 10:36:31 -04:00
Jarrod Johnson a7b8f0ab0c Parallelize cross-manager requests
Rather than doing it at one at a time, parallelize the requests
for improved performance.
2018-07-17 10:07:32 -04:00
Jarrod Johnson 3ab4203104 Explicitly set ECDHE curve
Some vintages of the SSL stack require we explicitly request a curve,
so here it is.
2018-07-16 16:23:33 -04:00
Jarrod Johnson 13aa2e9aae Catch more broad errors
Operating on a closed socket is not a socket.error
2018-07-16 11:58:18 -04:00
Jarrod Johnson 7462bc28e8 Use the eventlet socket in configmanager 2018-07-16 10:06:53 -04:00
Jarrod Johnson 18f1c07d65 Change to setting an errstr rather than exception
If nodefirmware update has an issue, provide error message instead.
2018-07-16 09:03:02 -04:00
Jarrod Johnson 0016077bee Ensure that wait_for_sync always does a new sync
If a sync is in progress, wait for that to complete.

Then issue the requested *new* sync.

Probably only needed if fullsync, as the one in progress may be a
'dirty' only sync and fullsync would be satisfied by the partial sync
without it, which is bad.
2018-07-13 22:15:38 -04:00
Jarrod Johnson 1dad69097b Be consistent with sync during load of leader cfg
Pass through sync as appropriate.

Also changes meant for previous commit
2018-07-13 21:52:17 -04:00
Jarrod Johnson fd7c428d1f Cleanup leftover sockets and more reliably be following or leading
Before there was a chance to be in a half state, leading to an inability
to reach consensus on leader.
2018-07-13 21:20:42 -04:00
Jarrod Johnson 80a1bd72e7 Correct arguments for Thread constructor 2018-07-13 15:43:09 -04:00
Jarrod Johnson 042d7ab5cf Modify clear_commit to use the same thread
Additionally, wrap a lock around the dbm operations, in case something
in the future makes a mistake.
2018-07-13 15:27:16 -04:00
Jarrod Johnson c74fdf5924 More collective join errors 2018-07-13 11:07:39 -04:00
Jarrod Johnson 58bf226d23 Relay error from server about token issue 2018-07-13 10:50:17 -04:00
Jarrod Johnson 6f012b69a1 Provide cleaner message for collective manager being unreachable 2018-07-13 10:43:20 -04:00
Jarrod Johnson 7f1e5d2302 Add explanation of 'all' in nodeattrib man page 2018-07-13 09:57:23 -04:00
Jarrod Johnson 3e2a827ff9 Correct typo in nodeattrib man page 2018-07-13 09:50:08 -04:00
Jarrod Johnson 1d16534c16 If replacing a follower stream, ensure the old one closes 2018-07-13 09:37:00 -04:00
Jarrod Johnson c80ebb0e8d Explicitly close connection before replacement
If an existing follower is stalled out, close the socket explicitly
to avoid leaving it open in lsof.
2018-07-13 09:14:36 -04:00
Jarrod Johnson efaf1dae70 Make cfgleader modifications more robust
If cfgleader is about to forget a socket, explicitly try to close
it first.
2018-07-13 09:05:28 -04:00
Jarrod Johnson 1de82936ed Add full sync mode
For implementing clear config, all data must be presumed dirty.
2018-07-12 17:06:37 -04:00
Jarrod Johnson b0c384c9ca Check quorum on attribute read
It's too bizarre for attribute read from api to work
without quorum, could be misleading.
2018-07-12 16:05:04 -04:00
Jarrod Johnson 61dd71778f Never generate new key on crypt read
An autogenerated key on read can never be useful.  Instead, let it fail
and assume a repair action is coming.
2018-07-12 15:55:05 -04:00
Jarrod Johnson 0f3014957b Fix non-ascii unicode handling of consoles 2018-07-12 14:16:44 -04:00
Jarrod Johnson c925353f02 Fix rollback
First the data was not actually being staged in the rollback area.
Secondly, there wasn't an assurance that the disk wouldn't have rollback
committed...
2018-07-12 10:01:32 -04:00
Jarrod Johnson 9edb225bd3 Fix the reference to sync to file 2018-07-12 09:20:41 -04:00
Jarrod Johnson 7cdc3c1400 Implement clear config rollback
Should something go awry during config
load, rollback the clear and load.
2018-07-12 08:48:21 -04:00
Jarrod Johnson bd2a3f14e6 Defer txcount increment until after potential failure
This avoids the txcount incrementing when no transaction actually
occurs.
2018-07-12 08:41:07 -04:00
Jarrod Johnson 87d00b7447 Fix typo in manpage for nodeattrib 2018-07-11 16:48:41 -04:00
Jarrod Johnson beedfb0600 If a drone doesn't exist, treat it as if it's an invalid certificate 2018-07-11 16:29:45 -04:00
Jarrod Johnson ce59a36351 Avoid excessive syncs on connect
This removes some redundancy and avoids writing and loading to disk
during the initialization process.
2018-07-11 16:07:56 -04:00
Jarrod Johnson a1e612968e Merge branch 'clustertime' of github.com:jjohnson42/confluent into clustertime 2018-07-11 13:44:30 -04:00
Jarrod Johnson ce1a58bf58 Provide a more specific error when file doesn't exist
nodemedia does check locally, but server should also check it, in
case of remote *and* service nodes.
2018-07-11 13:17:37 -04:00
Jarrod Johnson b386084f2d Note future enhancement for flattening on collective manager change... 2018-07-11 11:07:59 -04:00
Jarrod Johnson 8e9bcbb44f Clear txcount on enroll
The transaction count on 'join' was being honored as high, when
it never should be.
2018-07-11 09:40:22 -04:00
Jarrod Johnson 704aaeecf9 Tolerate newline in myname
vim is quite insistent on adding a newline, tolerate that.
2018-07-11 09:36:51 -04:00
Jarrod Johnson 11968faffc Numerous fixes to collective
If client has higher transaction count, do not close the connection
before extracting peer address.

If our connect session is rudely terminated, abort rather than trying
to continue.

On assimilate failure, ignore a failed assimilate with no data.

Fix problem where a follower getting double deleted was causing an error.
2018-07-10 14:55:57 -04:00
Jarrod Johnson 8769c438c0 Relax cryptodomex requirement
We don't *need* the higher version, it just accelerates password auth
if possible.  Fix conflict with RH provided package.
2018-07-10 10:10:04 -04:00
Jarrod Johnson f1489bf527 Add all to SYNOPSIS of nodeattrib 2018-07-09 16:52:07 -04:00
Jarrod Johnson c03781c022 Add 'all' to usage message of nodeattrib 2018-07-09 16:49:45 -04:00
Jarrod Johnson 298e11f60f Allow invite from non-leader role
A non-leader transaction is modified such that the enroll node
can be connected to the leader and have validation.
2018-07-09 16:40:43 -04:00
Jarrod Johnson 67d6e9a6c7 Add collective show
Provide a harmless way to look at collective state
2018-07-09 15:07:24 -04:00
Jarrod Johnson a4edf9afb8 Rename confluentutil to collective
Also adjust output to be a bit more automation friendly.
2018-07-09 13:33:56 -04:00
Jarrod Johnson 2342fe717e Remove superfluous call to sync to file
load_from_json already makes the call, remove the extra call that is
redundant.
2018-07-09 12:59:37 -04:00
Jarrod Johnson 08cf698609 Only conditionally require ffi
Only collective mode requires ffi, do not incur requirement for
non-collective mode.
2018-07-09 09:41:10 -04:00
Jarrod Johnson a905ae4865 Only zap cfgleader if not set
stale relay_slaved_requests was trouncing following status, correct
by avoiding zapping that state
2018-07-03 14:43:23 -04:00
Jarrod Johnson 1eaf5357ca Resolve race conditions on simultaneous collective outage
Implement random backoff strategy for serializing connect out and
connect in.
2018-07-03 14:09:09 -04:00
Jarrod Johnson 39378170b1 Add an error if cfgstreams loses a follower 2018-07-03 11:13:23 -04:00
Jarrod Johnson 2156e99ae4 Use alternative name for pycryptodomex 2018-07-03 10:43:05 -04:00
Jarrod Johnson bba12ed9e7 Update requirements to pull in cryptodomex 2018-07-03 10:32:33 -04:00
Jarrod Johnson 282043ed97 Switch to cryptodome
Cryptodome is a modern, but compatible replacement for pycrypto.

We may move to cryptography eventually, but start with this for now
for some nice speedups in some cases.
2018-07-03 10:31:13 -04:00
Jarrod Johnson 09c239b294 Fix memory leaks
For one, configmanager was left with stale callback references, clean
those up.

For another, the callback pattern was creating a circular reference that
python memory management couldn't overcome.  Break the reference
explicity when an item is disposed of.
2018-07-03 08:58:32 -04:00
Jarrod Johnson 0b26d12837 Fix memory leaks
For one, configmanager was left with stale callback references, clean
those up.

For another, the callback pattern was creating a circular reference that
python memory management couldn't overcome.  Break the reference
explicity when an item is disposed of.
2018-07-03 08:58:11 -04:00
Jarrod Johnson 956faee052 Correct typo in variable name 2018-06-28 14:12:56 -04:00
Jarrod Johnson 8e77466875 Carry txcount through connect replica
The txcount was not up to date when offline updates occurred.
2018-06-28 13:54:31 -04:00
Jarrod Johnson f01c7e19f7 Fix HA healing problems
If we are superior to leader, become leader
When abandoned by a leader, forget the leader.
2018-06-28 13:51:52 -04:00
Jarrod Johnson 5d894912ac Clean up more potential for CLOSE_WAIT
Explicitly close sockets in a few more places.
2018-06-28 10:50:03 -04:00
Jarrod Johnson 93e78d1f03 Fix try_assimilate
Also get rid of CLOSE_WAIT in some situations.
2018-06-28 09:53:34 -04:00
Jarrod Johnson 97f932b946 Fix the attempt to assimilate
In the wake of leader loss, the assimilate attempt was causing one
of a couple of bad behaviors, a trace if broken and if it should
work, the format of the data payload was incorrect.
2018-06-26 15:29:51 -04:00
Jarrod Johnson 61f24f4d8a Fix mismatched braces in previous commit 2018-06-26 15:09:17 -04:00
Jarrod Johnson 68a79695fc Add check for quorum to invite generation process
If a would-be collective member has no quorum, provide a clear
message indicating this as an issue.
2018-06-26 14:55:42 -04:00
Jarrod Johnson 401352998c Correctly show the error on non-leader
When non-leader tries to invite, print the error rather than unhelpful
exception with no helpful data.
2018-06-26 14:35:23 -04:00
Jarrod Johnson 9eeede651e Error when inviting from non leader 2018-06-26 14:24:52 -04:00
Jarrod Johnson fb98dd5636 Fix packaging issues 2018-06-26 14:12:53 -04:00
Jarrod Johnson 0843b991ea Isolate following to dedicated greenthread and put fallback to assert leadership 2018-06-26 14:06:01 -04:00
Jarrod Johnson 11e6145a46 Add quorum check to non-config requests 2018-06-26 13:52:20 -04:00
Jarrod Johnson 7433dd3e38 Wrap cfg init on follow in lock
Use a lock to provide more atomic behavior for connecting should
something go wrong in calling connect_to_leader incorrectly.
2018-06-26 10:13:27 -04:00
Jarrod Johnson 4de1fea7aa Implement attempt to assimilate 2018-06-25 17:30:29 -04:00
Jarrod Johnson f6342dd31f Allow connect_to_leader to cycle in the parent for loop
Startup was foiled when one entry was bad.  Also add comments
on invite/join needing to be done from current leader, and the need
for better error messages.
2018-06-25 14:51:39 -04:00
Jarrod Johnson 0499a14fe8 Try to reestablish collective on leader loss 2018-06-25 10:40:29 -04:00
Jarrod Johnson f301cd272f Have follower notice lost leader
This will mitigate period during which requests
hang instead of error.
2018-06-24 11:08:15 -04:00
Jarrod Johnson bf4f5ad5ae Recognize loss of follower as step toward loss of quorum
Properly reap the loss of a follower.
2018-06-22 16:17:48 -04:00
Jarrod Johnson 5a5f0169a7 Fix logic on null messages 2018-06-22 15:46:41 -04:00
Jarrod Johnson 03adec089d Also clear cfgleader when actually becoming leader 2018-06-22 15:26:08 -04:00
Jarrod Johnson f065fafd61 Clear the quorum block on initial xfer
The initial transfer needs to have the configmanager working locally.
2018-06-22 15:23:20 -04:00
Jarrod Johnson b315042850 Error if starting without quorum
If collective mode is present, but no candidates worked, still error
out.
2018-06-22 15:12:42 -04:00
Jarrod Johnson 5588712320 Clear transaction count on config clear
A clear configuration should have 0 transactions.
2018-06-22 14:46:52 -04:00
Jarrod Johnson c6a0aeca3b Fix dispatch of commands with InputData
Inputdata needed to be serialized for the network.  Further, had
to have a JSON-safe payload for indicating name for certificate look
up, to avoid doing pickle load on client input prior to client
validation.
2018-06-22 14:41:41 -04:00
Jarrod Johnson f45228c067 Auto-migrate open console session on loss of management
This will keep consoles connected across a manager change.  Note
that as it stands, a console session enduring multiple changes will
become increasingly convoluted as the redirect chain will increase
every time, rather than shorting back to the entry point.
2018-06-21 15:14:56 -04:00
Jarrod Johnson d34e65f9b7 Fix tlvdata handling of unicode input
Unicode input is normalized to bytes.  Also have to handle python3
not having 'unicode', do a quick change to support that in both.
2018-06-21 14:29:54 -04:00
Jarrod Johnson baef8c2c42 Connect and fix the proxyconsole
This works full duplex for sockapi and read for web consoles.
2018-06-21 13:46:51 -04:00
Jarrod Johnson 1543e145b7 Draft for proxyconsole object for remote use of consoles
This would be the stub stand in for the console object to
connect to remote console object rather than local.
2018-06-20 16:36:59 -04:00
Jarrod Johnson 2d403f7d68 Defer import of confluent log
confluent.util pulls in log more cleanly, for now rearrange for
easier time running slp test mode.
2018-06-20 14:56:07 -04:00
Jarrod Johnson 78117a1b1a Draft proxyconsole support for sockapi
Foundation for consoleserver to be able to do backend to backend
connections
2018-06-19 16:50:49 -04:00
Jarrod Johnson 624012774c Discontinue processing on cert mismatch
If cert mismatched, the client was shut out, but processing continued,
fix this mistake.
2018-06-19 16:45:06 -04:00
Jarrod Johnson 003358da5f Discontinue ipmi session on collective manager change 2018-06-19 15:10:59 -04:00
Jarrod Johnson 6b24b9691b Merge branch 'master' into clustertime 2018-06-19 11:07:53 -04:00
Jarrod Johnson 6ba8ca2fa2 Remove accidental change
keepalive was disabled, which negatively impacted
web ui performance.  Re-enable.
2018-06-19 11:07:23 -04:00
Jarrod Johnson 38898ca921 Auto-make certificate if missing
Automatically fix a missing certificate if this is the case.
2018-06-19 11:05:38 -04:00
Jarrod Johnson 810be71720 Initial support for non-console dispatch
For non-exceptional cases, it is now functional.
2018-06-15 15:54:26 -04:00
Jarrod Johnson b877a95645 Include absent devices in the json of nodeinventory 2018-06-15 11:03:03 -04:00
Jarrod Johnson efd5732682 Amend json output
Have the nodeinventory json output in a bit more directly useful format,
rather than regarding the API structured JSON...
2018-06-15 11:02:57 -04:00
Jarrod Johnson 4906d6e9c4 Add --json to nodeinventory
Have nodeinventory have an option to output in json.
2018-06-15 11:02:51 -04:00
Jarrod Johnson f2500d9d27 Add general confluentutil command
This provides util commands to manage certificates and collective
membership.
2018-06-13 16:23:49 -04:00
Jarrod Johnson 0507e89da8 Add ability to skip key backup and interactive password
Backups should carefully protect keys.json, but that's only feasible
interactively.  However keys don't change, so have a way to combine
protected keys.json with password with relatively safe non-interactive
incremental backups.
2018-06-13 16:22:40 -04:00
Jarrod Johnson 8cea5a4fed Fix redacted db dump
The db dump function did not trigger the init() function.
Rearrange the collective section to occur after a section that does
ensure the configmanager is initted.
2018-06-13 09:15:27 -04:00
Jarrod Johnson 8515d43dad A shell script to illustrate generating ECDSA key
For now put down the openssl commands required to get the key and
certificate available.
2018-06-12 16:57:36 -04:00
Jarrod Johnson 5c12dc2cba Do not require exactly TLSv1.0
This was breaking TLSv1.2.
2018-06-08 10:15:38 -04:00
Jarrod Johnson a08eace00c Fix missing import of traceback 2018-06-05 13:08:05 -04:00
Jarrod Johnson cdb20c0302 Fix missing import of traceback 2018-06-05 13:05:42 -04:00
Jarrod Johnson 3eed46ec08 Disconnect on loss of ownership 2018-06-02 12:36:20 -04:00
Jarrod Johnson daef9fa60b Fix confusing nodeconfig error handling
Properly react to error conditions
2018-06-01 16:48:34 -04:00
Jarrod Johnson a7a4ede580 Fix confusing nodeconfig error handling
Properly react to error conditions
2018-06-01 16:48:19 -04:00
Jarrod Johnson a560dc1974 Add timeout on httpapi socket
Clients that fail to send any data, or keep a persistent socket
open without using it are killed off.
2018-06-01 16:26:21 -04:00
Jarrod Johnson e8cea66a85 Add timeout on httpapi socket
Clients that fail to send any data, or keep a persistent socket
open without using it are killed off.
2018-06-01 16:25:38 -04:00
Jarrod Johnson 8fc29d1b46 Correctly allow manual discovery through ambiguous situation
Manual discovery may 'catch' some incidental data from auto-discovery.
Since the operation is manual, trust the user rather than assume the
user is confused.
2018-06-01 16:09:32 -04:00
Jarrod Johnson 6e0186947f Correctly allow manual discovery through ambiguous situation
Manual discovery may 'catch' some incidental data from auto-discovery.
Since the operation is manual, trust the user rather than assume the
user is confused.
2018-06-01 16:09:13 -04:00
Jarrod Johnson a45a0e31f1 Merge branch 'master' of github.com:jjohnson42/confluent 2018-06-01 15:54:31 -04:00
Jarrod Johnson 8ea532053e Add guardrail around slp snoop
If a program error should befall our poor slp service, log the issue
and carry on.
2018-06-01 15:54:27 -04:00
Jarrod Johnson 366c955956 Add guardrail around slp snoop
If a program error should befall our poor slp service, log the issue
and carry on.
2018-06-01 15:53:52 -04:00
Jarrod Johnson d968fb6b04 Add TODO note on how to do the collective console sessions
We will hove consoleserver abstract this away from sockapi/httpapi
concerns.
2018-05-31 16:22:11 -04:00
Jarrod Johnson db1d5d6dff Prepare for request dispatch
Sort and exclude nodes that have collective.manager, prepare to relay
for dispatch.
2018-05-31 16:18:58 -04:00
Jarrod Johnson 867dd0dda7 Handle collective.manager being set back to the node 2018-05-31 16:16:03 -04:00
Jarrod Johnson 22b63df036 First pass at suppressing foreign consoles
If console session is another node, prevent it from working locally.
Focus first on making sure the wrong nodes don't work before routing.
2018-05-31 15:53:09 -04:00
Jarrod Johnson 54f419d9b4 Add 'collective.manager'
For requests that must be routed to a definitive owner (e.g. IPMI),
have an attribute to track the currently responsible server for
singleton operations.
2018-05-31 15:47:19 -04:00
Jarrod Johnson 5d6e241287 Fix deadlock on collective create user
There was a call to rpc-out from within a 'true' function, which is bad,
fix this by only calling the 'true' function from 'true' function.
2018-05-30 16:21:40 -04:00
Jarrod Johnson 417bc5acda Fix incorrect function call for user creation
In collective mode, the incorrect rpc call was made
2018-05-30 15:30:27 -04:00
Jarrod Johnson 57ffe166d3 Merge branch 'master' into clustertime 2018-05-25 10:24:34 -04:00
Jarrod Johnson 5718c60a51 Merge branch 'clustertime' of github.com:jjohnson42/confluent into clustertime 2018-05-25 10:23:25 -04:00
Jarrod Johnson 31effcc025 Fix mistake in variable name in nodeconfig 2018-05-25 10:22:35 -04:00
Jarrod Johnson cefca49128 Fix mistake in variable name in nodeconfig 2018-05-25 10:21:34 -04:00
Jarrod Johnson 41a5eaa464 Merge branch 'clustertime' of github.com:jjohnson42/confluent into clustertime 2018-05-23 13:02:12 -04:00
Jarrod Johnson 46c4065b81 Correct another typo 2018-05-23 13:02:03 -04:00
Jarrod Johnson 57e323786e Fix syntax error in the recent code 2018-05-22 11:00:30 -04:00
Jarrod Johnson 3b2a18a650 Merge branch 'master' into clustertime 2018-05-22 10:34:31 -04:00
Jarrod Johnson 3ace7747ab Fix typo 2018-05-22 10:11:37 -04:00
Jarrod Johnson 8ede0fd8ef Document {{}} escape on noderun and nodeshell
Documentation did not explain that
2018-05-22 09:59:30 -04:00
Jarrod Johnson be3ecf60a5 Fix bad error message on {} in nodeshell/noderun
{} used in awk is likely, give proper error message.
2018-05-22 09:56:53 -04:00
Jarrod Johnson 8807fcfd22 Fix missing portname in lldp data
Root cause was pysnmp returning extraneous leftover data causing
calling code to overrite good data.
2018-05-22 09:37:01 -04:00
Jarrod Johnson 33fe0a3db4 Fix wrong port name for G8332
Was using the incorrect half of the return, which broke on G8332.
2018-05-22 09:36:55 -04:00
Jarrod Johnson ca7711b373 Fix missing portname in lldp data
Root cause was pysnmp returning extraneous leftover data causing
calling code to overrite good data.
2018-05-22 09:36:09 -04:00
Jarrod Johnson 8b37199654 Fix wrong port name for G8332
Was using the incorrect half of the return, which broke on G8332.
2018-05-22 09:34:02 -04:00
Jarrod Johnson ff2bc89fae Merge branch 'master' into clustertime 2018-05-21 15:53:48 -04:00
Jarrod Johnson 5fe2d2a31c Fix unprintable characters in some chassisid
Some switches send raw octets back, some printable.  Try to normalize
when unprintable chassis id are detected.  This is not 100%, if the hex
would be all between 20 and 80 throughout the string, then this will
fail to do the right thing.

Hopefully, the amount of times when lldp partners disagree on how to
implement LLDP-MIB will be limited.  Currently it is known than Lenovo
and Juniper switches disagree, and both of those have what would
be unprintable values in the mfg portion of the chassis id.
2018-05-21 15:53:42 -04:00
Jarrod Johnson a4fed0601c Fix unprintable characters in some chassisid
Some switches send raw octets back, some printable.  Try to normalize
when unprintable chassis id are detected.  This is not 100%, if the hex
would be all between 20 and 80 throughout the string, then this will
fail to do the right thing.

Hopefully, the amount of times when lldp partners disagree on how to
implement LLDP-MIB will be limited.  Currently it is known than Lenovo
and Juniper switches disagree, and both of those have what would
be unprintable values in the mfg portion of the chassis id.
2018-05-21 15:53:12 -04:00
Jarrod Johnson 41298a8e01 Extend collective data functions to more functions
Add to users and groups.  Refactor reusable code.
Code that remains still looks awfully repetitive though...
2018-05-21 15:46:51 -04:00
Jarrod Johnson caa4000b7e Merge branch 'master' into clustertime 2018-05-21 11:49:19 -04:00
Jarrod Johnson fde2c7a8e0 Fix the encuuid reference
encuuid is a list, not the value, so get the first value
rather than try to concatenate the string.
2018-05-18 11:49:06 -04:00
Jarrod Johnson fbbb5d048f Fix the encuuid reference
encuuid is a list, not the value, so get the first value
rather than try to concatenate the string.
2018-05-18 11:47:34 -04:00
Jarrod Johnson 32d60145f7 Fix typo in discovery core 2018-05-18 10:20:57 -04:00
Jarrod Johnson 1db781852c Fix typo in discovery core 2018-05-18 10:20:31 -04:00
Jarrod Johnson 0dbf82b0f1 Clean up errors on bad ipv4 addresses
confluent errors are better now
2018-05-17 16:24:31 -04:00
Jarrod Johnson 675dc966c7 Clean up errors on bad ipv4 addresses
confluent errors are better now
2018-05-17 16:24:06 -04:00
Jarrod Johnson a9485706d1 Update warning to be commented out, just in case.. 2018-05-17 15:40:59 -04:00
Jarrod Johnson db1ae03415 Sample script for mac to ipv6 translation
Useful for some generic applications where nodediscover
does not have full support, but must be used with care
as it doesn't guarantee the mac address is what we expect
it to be.
2018-05-17 15:40:49 -04:00
Jarrod Johnson 9826235d4d Update warning to be commented out, just in case.. 2018-05-17 15:40:20 -04:00
Jarrod Johnson 232140899e Sample script for mac to ipv6 translation
Useful for some generic applications where nodediscover
does not have full support, but must be used with care
as it doesn't guarantee the mac address is what we expect
it to be.
2018-05-17 15:35:52 -04:00
Jarrod Johnson 5dddae0ebf Cleaner handling of invalid names in restore attempt
Detect problems ahead af time and more cleanly print a message.
2018-05-17 14:40:40 -04:00
Jarrod Johnson 39e9bf0be5 Cleaner handling of invalid names in restore attempt
Detect problems ahead af time and more cleanly print a message.
2018-05-17 14:40:19 -04:00
Jarrod Johnson d6b7c536d5 Fix discovery of old SMM firmware
Older SMM firmware will not have neighbor data, ignore and move on
in such a case.
2018-05-17 14:21:24 -04:00
Jarrod Johnson f21db46cdd Fix discovery of old SMM firmware
Older SMM firmware will not have neighbor data, ignore and move on
in such a case.
2018-05-17 14:20:59 -04:00
Jarrod Johnson 2d1ba7cc9b Merge branch 'master' into clustertime 2018-05-17 13:13:46 -04:00
Jarrod Johnson 22049002bb Fix exitcode references before use 2018-05-17 11:11:11 -04:00
Jarrod Johnson 727aa9a56c Merge branch 'clustertime' of github.com:jjohnson42/confluent into clustertime 2018-05-16 11:28:08 -04:00
Jarrod Johnson dcb1c2b32b Fix load of txcount
Mistake caused txcount not to restore from disk.
2018-05-16 11:27:46 -04:00
Jarrod Johnson d705d6320a Start setting the stage for leader change on restart
Have connect() have a way to recover if leader is dead.

Also these will be involved in configmanager detected loss of leader
2018-05-16 11:27:46 -04:00
Jarrod Johnson 52e2038fdf Fix transaction count in collective
Slave members were not persisting the value to disk
2018-05-16 11:27:46 -04:00
Jarrod Johnson 9d58a2d382 Correct scope of currentleader 2018-05-16 11:27:46 -04:00
Jarrod Johnson a2187087f7 Fix not having currentleader set
A slave node now recognizes itself as such.
2018-05-16 11:27:46 -04:00
Jarrod Johnson c5b5178f39 Block some early startup problems in collective 2018-05-16 11:27:46 -04:00
Jarrod Johnson ff026ee034 Include absent devices in the json of nodeinventory 2018-05-16 11:27:46 -04:00
Jarrod Johnson 1cc659a3b0 Amend json output
Have the nodeinventory json output in a bit more directly useful format,
rather than regarding the API structured JSON...
2018-05-16 11:27:46 -04:00
Jarrod Johnson 8bc8faf0bc Add --json to nodeinventory
Have nodeinventory have an option to output in json.
2018-05-16 11:27:46 -04:00
Jarrod Johnson 1c2c9931a8 Persist the transactioncount
Needed for eventually ascertaining the viability in selecting leader.
2018-05-16 11:27:46 -04:00
Jarrod Johnson 778a153170 Correct spelling error 2018-05-16 11:27:46 -04:00
Jarrod Johnson 34c510e30a Try to persist name as myname
hostname may not agree with the name chosen by user, in such a case
persist the name and use that, falling back to gethostname()
as needed.
2018-05-16 11:27:46 -04:00
Jarrod Johnson d4babbffa4 Check and try to start collective on startup
Not yet good enough for a leader to rejoin, but enough for a follower
to rejoin automatically.
2018-05-16 11:27:46 -04:00
Jarrod Johnson 1c930eba9d Have attrib set wait on all collective members
This will mean that it is reliable that a nodeattrib ; <command>
in delegation scenarios is guaranteed to execute in order.
2018-05-16 11:27:46 -04:00
Jarrod Johnson c4b564123f Allow slave collective drones to set
It works (once), but needs xid fix.
2018-05-16 11:27:46 -04:00
Jarrod Johnson 6d728df4dc Fix reuse of channel for receiving changes 2018-05-16 11:27:46 -04:00
Jarrod Johnson f1e29393df Succeed in pushing config to followers from leader
Still more work to be done for multiple transactions.
2018-05-16 11:27:46 -04:00
Jarrod Johnson 81bb16476c Apply changes from leader subscription 2018-05-16 11:27:46 -04:00
Jarrod Johnson 035f10e7d7 Rough draft for ongoing syncronization
Putting thoughts down on how xmit will work, will add recv and relay,
do some testing, and then decide how much can be done to apply it neatly
to the various points.
2018-05-16 11:27:46 -04:00
Jarrod Johnson 830e6bb4e4 Clear configuration prior to sync 2018-05-16 11:27:46 -04:00
Jarrod Johnson 1eb542f6a8 Actually execute replicate-on-connect
This creates a duplicate of the leader.
2018-05-16 11:27:46 -04:00
Jarrod Johnson b733049a0c Add self to collective database
Database would omit initial leader otherwise.
2018-05-16 11:27:46 -04:00
Jarrod Johnson a4d80e4e3a Fixes to the connect draft
Needed to track it's own name, skip the banner and auth message...
2018-05-16 11:27:46 -04:00
Jarrod Johnson a69b5fbb50 For enroll, track the remote cert special
For reconnect, we will have collective objects.  However at
enroll time, we need to be special.
2018-05-16 11:27:46 -04:00
Jarrod Johnson 789dfe94d0 Fix missing import of eventlet
Unable to spawn the connect thread due to missing import.
2018-05-16 11:27:46 -04:00
Jarrod Johnson 73a376fd74 Fix backup of globals
Globals failed to open the backup file as writable, causing failure if
a global had been set.
2018-05-16 11:27:46 -04:00
Jarrod Johnson 57f390fd0a Draft for starting the databse replication
Does not actually heed the data, or implement ongoing relay of data back and forth.
2018-05-16 11:27:46 -04:00
Jarrod Johnson 641bc7344a Add hooks for collective mode and refactor
In support of config replication, need configmanager to do a few things
2018-05-16 11:27:46 -04:00
Jarrod Johnson af940c972f Add function to check address equivalence
As we start needing to compare addresses, provide a central function
to handle the various oddities associated with that.
2018-05-16 11:27:46 -04:00
Jarrod Johnson 468f00cd1c Rename 'joinchallenge' to 'enroll'
Seems like a better word to use.
2018-05-16 11:27:46 -04:00
Jarrod Johnson ce635068aa Begin the 'connect' collective operation
First check if we are current leader, reject if not, then if cert
is invalid, reject, then comes the TODO.
2018-05-16 11:27:46 -04:00
Jarrod Johnson 348c6a7c38 Add collective info to DB backup
Now persisted to disk *and* accessible to backup.
2018-05-16 11:27:46 -04:00
Jarrod Johnson a41a42ffd0 Persint collective info to disk
Additionally, simplify the concluding steps of the join conversation.
2018-05-16 11:27:46 -04:00
Jarrod Johnson 3a354a6300 Ensure the invitation works out to even multiple of 3 bytes
It's cosmetic, but a nice way to avoid '=' in the tokens.
2018-05-16 11:27:46 -04:00
Jarrod Johnson fb9925bb84 Fix encoding of the response proof
The response was not decoded, causing it to always fail.
2018-05-16 11:27:46 -04:00
Jarrod Johnson 78bf1d5acd Provide more feedback and fix some flow issues 2018-05-16 11:27:46 -04:00
Jarrod Johnson 8165b645d9 Fix invite process and unicode
Unicode strings do not fit with our world view, make them bytes.
2018-05-16 11:27:46 -04:00
Jarrod Johnson c2783b6734 Rename swarm to collective in setup.py.tmpl 2018-05-16 11:27:46 -04:00
Jarrod Johnson 033d59b04a Afetr some feedback, rename it 'collective' 2018-05-16 11:27:46 -04:00
Jarrod Johnson 4155954d1c Add swarm to setup.py
Make sure the swarm content is actually installed.
2018-05-16 11:27:46 -04:00
Jarrod Johnson 1b912c4365 Further advance the swarm concept
This marks the start of attempting to connect the invitation
to sockets and using the invitation to measure the certificates as
well as proving client knowledge of an invitation token.
2018-05-16 11:27:46 -04:00
Jarrod Johnson 5f9ee3d3c5 Migrate 'multimanager' to 'swarm'
It's easier to say 'swarm' and conveys the sense without confusion
of 'cluster' mode.
2018-05-16 11:27:46 -04:00
Jarrod Johnson cc9becea3b Add ability to get client certificates
Unfortunately, to pull off the target user experience, we
must register a custom client certificate validation to allow
us to not require a CA.
2018-05-16 11:27:46 -04:00
Jarrod Johnson 1e0cf7e9fb Create invitation management module
This facilitates the generation of invitations and logistics of proving
knowledge of the invitation and the integrity of the certificates.
peercert is to be gotten through getpeercert(binary_form=True) and
local cert through the util function to load from file, since we don't
have another way of getting local certificate.
2018-05-16 11:26:36 -04:00
Jarrod Johnson 7ebe9da24b Add utility function to get certificate from file
This can be used to get our own certificate, for use in the
multimanager membership establishment.
2018-05-16 11:26:36 -04:00
Jarrod Johnson 6cba560f6a Fix nodeconfig handling of general errors
nodeconfig was not handling errors in results well, fix this by
refactoring the nodefirmware facility into it.
2018-05-16 11:21:26 -04:00
Jarrod Johnson 08dcab4c72 Fix load of txcount
Mistake caused txcount not to restore from disk.
2018-05-14 16:25:27 -04:00
Jarrod Johnson 4f73ddc41e Start setting the stage for leader change on restart
Have connect() have a way to recover if leader is dead.

Also these will be involved in configmanager detected loss of leader
2018-05-14 16:22:27 -04:00
Jarrod Johnson 7a912b31cb Fix transaction count in collective
Slave members were not persisting the value to disk
2018-05-14 15:35:44 -04:00
Jarrod Johnson 297513bba7 Correct scope of currentleader 2018-05-11 15:03:41 -04:00
Jarrod Johnson aa2be98dc3 Fix not having currentleader set
A slave node now recognizes itself as such.
2018-05-11 15:00:18 -04:00
Jarrod Johnson 3cc9ee1a17 Block some early startup problems in collective 2018-05-11 14:49:46 -04:00
Jarrod Johnson 173f1eaf7e Include absent devices in the json of nodeinventory 2018-05-11 14:24:47 -04:00
Jarrod Johnson 0d4b1a4213 Amend json output
Have the nodeinventory json output in a bit more directly useful format,
rather than regarding the API structured JSON...
2018-05-11 14:18:04 -04:00
Jarrod Johnson 58155a47b5 Add --json to nodeinventory
Have nodeinventory have an option to output in json.
2018-05-11 13:49:54 -04:00
Jarrod Johnson 7fa431dbc9 Persist the transactioncount
Needed for eventually ascertaining the viability in selecting leader.
2018-05-11 11:53:45 -04:00
Jarrod Johnson e98ecd9867 Correct spelling error 2018-05-10 16:46:29 -04:00
Jarrod Johnson 5087c8bed5 Try to persist name as myname
hostname may not agree with the name chosen by user, in such a case
persist the name and use that, falling back to gethostname()
as needed.
2018-05-10 16:40:13 -04:00
Jarrod Johnson 0477ab7d85 Check and try to start collective on startup
Not yet good enough for a leader to rejoin, but enough for a follower
to rejoin automatically.
2018-05-10 16:19:46 -04:00
Jarrod Johnson 267d83e6e4 Have attrib set wait on all collective members
This will mean that it is reliable that a nodeattrib ; <command>
in delegation scenarios is guaranteed to execute in order.
2018-05-09 17:01:23 -04:00
Jarrod Johnson c962d10222 Allow slave collective drones to set
It works (once), but needs xid fix.
2018-05-08 16:53:59 -04:00
Jarrod Johnson e5f553801b Fix reuse of channel for receiving changes 2018-05-08 13:35:30 -04:00
Jarrod Johnson d11c716b6a Succeed in pushing config to followers from leader
Still more work to be done for multiple transactions.
2018-05-08 11:33:42 -04:00
Jarrod Johnson aec4e746e9 Apply changes from leader subscription 2018-05-04 16:12:53 -04:00
Jarrod Johnson a78aa6816c Rough draft for ongoing syncronization
Putting thoughts down on how xmit will work, will add recv and relay,
do some testing, and then decide how much can be done to apply it neatly
to the various points.
2018-05-04 15:16:30 -04:00
Jarrod Johnson 5abaddfe63 Clear configuration prior to sync 2018-05-04 12:19:45 -04:00
Jarrod Johnson ecfc56efde Actually execute replicate-on-connect
This creates a duplicate of the leader.
2018-05-03 14:03:56 -04:00
Jarrod Johnson ecfb4d68c5 Add self to collective database
Database would omit initial leader otherwise.
2018-05-03 13:27:48 -04:00
Jarrod Johnson 855241a043 Fixes to the connect draft
Needed to track it's own name, skip the banner and auth message...
2018-05-03 13:18:08 -04:00
Jarrod Johnson ce4c72eae2 For enroll, track the remote cert special
For reconnect, we will have collective objects.  However at
enroll time, we need to be special.
2018-05-03 11:18:02 -04:00
Jarrod Johnson c8961377ed Fix missing import of eventlet
Unable to spawn the connect thread due to missing import.
2018-05-01 16:51:57 -04:00
Jarrod Johnson 1b17c42cae Fix backup of globals
Globals failed to open the backup file as writable, causing failure if
a global had been set.
2018-05-01 16:18:31 -04:00
Jarrod Johnson 196e8d0d58 Draft for starting the databse replication
Does not actually heed the data, or implement ongoing relay of data back and forth.
2018-04-30 16:20:49 -04:00
Jarrod Johnson dbb50f0807 Add hooks for collective mode and refactor
In support of config replication, need configmanager to do a few things
2018-04-30 16:09:28 -04:00
Jarrod Johnson 1200f7b7a1 Add function to check address equivalence
As we start needing to compare addresses, provide a central function
to handle the various oddities associated with that.
2018-04-30 16:08:15 -04:00
Jarrod Johnson a2a0b5de2c Rename 'joinchallenge' to 'enroll'
Seems like a better word to use.
2018-04-30 11:37:23 -04:00
Jarrod Johnson c7b01e00b6 Begin the 'connect' collective operation
First check if we are current leader, reject if not, then if cert
is invalid, reject, then comes the TODO.
2018-04-26 16:34:54 -04:00
Jarrod Johnson 06fdc648b8 Add collective info to DB backup
Now persisted to disk *and* accessible to backup.
2018-04-26 16:03:03 -04:00
Jarrod Johnson de89803b9c Persint collective info to disk
Additionally, simplify the concluding steps of the join conversation.
2018-04-26 15:48:15 -04:00
Jarrod Johnson d38d9204a7 Ensure the invitation works out to even multiple of 3 bytes
It's cosmetic, but a nice way to avoid '=' in the tokens.
2018-04-26 11:35:06 -04:00
Jarrod Johnson 1deb44021f Fix encoding of the response proof
The response was not decoded, causing it to always fail.
2018-04-25 20:49:08 -04:00
Jarrod Johnson 619bbbca96 Provide more feedback and fix some flow issues 2018-04-25 16:47:42 -04:00
Jarrod Johnson 8246ebdd2b Fix invite process and unicode
Unicode strings do not fit with our world view, make them bytes.
2018-04-25 14:21:12 -04:00
Jarrod Johnson a94a724fe0 Rename swarm to collective in setup.py.tmpl 2018-04-25 13:31:26 -04:00
Jarrod Johnson 6b9aed3722 Afetr some feedback, rename it 'collective' 2018-04-25 13:01:59 -04:00
Jarrod Johnson a3de8b9374 Add swarm to setup.py
Make sure the swarm content is actually installed.
2018-04-24 15:58:40 -04:00
Jarrod Johnson c8e5808daf Further advance the swarm concept
This marks the start of attempting to connect the invitation
to sockets and using the invitation to measure the certificates as
well as proving client knowledge of an invitation token.
2018-04-24 14:44:45 -04:00
Jarrod Johnson f3a0ccbff8 Migrate 'multimanager' to 'swarm'
It's easier to say 'swarm' and conveys the sense without confusion
of 'cluster' mode.
2018-04-24 12:59:24 -04:00
Jarrod Johnson 27c1355a4f Add ability to get client certificates
Unfortunately, to pull off the target user experience, we
must register a custom client certificate validation to allow
us to not require a CA.
2018-04-24 11:00:23 -04:00
Jarrod Johnson 7909f9e003 Switch to explicit SSL context when possible
This allows more fine grained control over the security parameters of
the TLS connection.
2018-04-23 14:18:51 -04:00
Jarrod Johnson 97d38efb29 Merge branch 'master' into clustertime 2018-04-23 11:13:22 -04:00
Jarrod Johnson 14ff33a44a Only activate the remote API socket if user makes cert
This prevents the useless networking socket from being opened
when it cannot be used.  This means most implementations will not
have an extra port to explain unless the user goes through the work
and knows what it would be.
2018-04-20 19:30:15 -04:00
Jarrod Johnson 78bdac474f Merge branch 'master' into clustertime 2018-04-20 13:25:16 -04:00
Jarrod Johnson 0481f7889b Make macmap api case insensitive
This helps usability of the api.
2018-04-20 13:25:02 -04:00
Jarrod Johnson 123a1a9dc1 Merge branch 'clustertime' of github.com:jjohnson42/confluent into clustertime 2018-04-17 11:10:13 -04:00
Jarrod Johnson fa24622704 Merge branch 'master' into clustertime 2018-04-17 11:09:59 -04:00
Jarrod Johnson a1156097d2 Add facility to disable autosense
discovery autosense at scale may produce undesirable performance.
Provide an interface to turn off the autosense.

If autosense is off, manual scan can still be performed.
2018-04-13 16:54:27 -04:00
Jarrod Johnson af72d0e71a Update the discovery lookup tables on node add/remove
This will mitigate stale mappings in the discovery process.
2018-04-12 17:05:06 -04:00
Jarrod Johnson 008f8e22ae Abort traversing gap in SMM chain
Once there is a gap, the next hop in the chain will be ambiguous.
Discovery must always precede from the front-most chassis.
2018-04-12 15:45:07 -04:00
Jarrod Johnson 39ee0da879 Fix makesetup for confluent_client
Fixing the redundant __init__.py led to no __init__.py, fix
that mistake.
2018-04-10 16:11:14 -04:00
Jarrod Johnson fc7b26eaf7 Remove __init__.py from tracking in client 2018-04-10 16:09:26 -04:00
Jarrod Johnson 91238f1dcb Clean up pure python packaging
Fix __init__.py redundancy, update requirements to current state
of affairs.
2018-04-10 16:06:37 -04:00
Jarrod Johnson 7f29d3a48f Merge branch 'master' into clustertime 2018-04-10 15:11:59 -04:00
Jarrod Johnson 76a4a91351 Fix pyparsing rpm name
Accept another likely formulation of an rpm name for
the package.
2018-04-10 15:11:20 -04:00
Jarrod Johnson 5ca52ff03b Handle interruptions to select such as resize
Resize can cause an interrupted operation on stdin, handle that.
2018-04-09 10:48:06 -04:00
Jarrod Johnson bd40f2f4a6 Fix mistake in indexing of url 2018-03-27 17:11:35 -04:00
Jarrod Johnson 66e8ce2dde Merge branch 'master' of github.com:jjohnson42/confluent 2018-03-27 16:35:31 -04:00
Jarrod Johnson 3dd86c71fd Add bmc.hostname to nodeconfig 2018-03-27 16:32:37 -04:00
Jarrod Johnson f97c39cea4 Add hostname to api
The hostname of the BMC is added to the api.
2018-03-27 15:51:14 -04:00
Jarrod Johnson 6671b9aad3 Provide cleaner behavior on timeouts
If a timeout occurred outside of a keeplaive, provide
a more consistent message about the situation.
2018-03-23 08:27:27 -04:00
Jarrod Johnson f88e0bca4c Fix nodeshell hang on incomplete lines
readline would hang because the filehandle was really not ready.
2018-03-19 08:45:13 -04:00
Jarrod Johnson afd366f134 Create invitation management module
This facilitates the generation of invitations and logistics of proving
knowledge of the invitation and the integrity of the certificates.
peercert is to be gotten through getpeercert(binary_form=True) and
local cert through the util function to load from file, since we don't
have another way of getting local certificate.
2018-03-15 19:22:03 -04:00
Jarrod Johnson ad0a7de1e3 Add utility function to get certificate from file
This can be used to get our own certificate, for use in the
multimanager membership establishment.
2018-03-15 18:59:49 -04:00
Jarrod Johnson 026a027603 Fix normalizing unicode in dicts with lists
If there's a list in a list, normalize that as well.
2018-03-15 12:55:32 -04:00
Jarrod Johnson 308db99dbb Fix inconsistent dict member extension
If two portions of a list come back piecewise from the plugin that
are both lists, extend them rather than making a nested list.
2018-03-15 12:09:45 -04:00
Jarrod Johnson a20b0abb43 Do not clear the buffer on superfluous reopen
If someone does a reopen, try to preserve the buffer, unless connect
proves there to be a deeper issue.  The risk of staleness is low, but
the experience of the whole screen clearing is tricky.  This was not
such an issue at the time, but using pyte causes clearbuffer to also
clear connected client terminals.
2018-03-14 17:00:44 -04:00
Jarrod Johnson 7413c44df8 Fix manual discovery
In manual discovery, maccount is not a field in the info, as no macmap
processing is done in manual.
2018-03-14 09:27:29 -04:00
Jarrod Johnson 463f61fac7 Modify XSS-Protection directive 2018-03-12 13:41:18 -04:00
Jarrod Johnson 0f60fc6df7 Fix uninitialized self._prevdict
self._prevdict was referenced without initialization.
2018-03-07 10:21:35 -05:00
Jarrod Johnson 110820e7b7 Revert "Accommodate XCC firmware behavior"
This reverts commit 9baa1f5652.
2018-03-06 15:52:53 -05:00
Jarrod Johnson 71214eb613 Revert "Correct indentation"
This reverts commit a2163244db.
2018-03-06 15:52:45 -05:00
Jarrod Johnson 889eda3d96 Merge remote-tracking branch 'upstream/master' 2018-03-06 11:25:54 -05:00
Jarrod Johnson 7593d21a87 Add missing exceptions import
exc was not imported
2018-03-06 11:25:36 -05:00
Jarrod Johnson 972801d41f Merge pull request #95 from aduffy19/nodepowerUpdate
Add previous option to nodepower command
2018-03-05 15:44:28 -05:00
Amanda Duffy b49531dfa5 Add previous option to nodepower command 2018-03-05 15:41:28 -05:00
Jarrod Johnson 3ae7d85820 Fix confluentdbgcli on screen resize 2018-03-01 13:39:25 -05:00
Jarrod Johnson 0d06eedc81 Move curruuid up so it is always set
If detected pre-discovered, curruuid was not being set correctly
2018-02-28 11:53:03 -05:00
Jarrod Johnson ca27385eaa Fix confluentdbutil restore with typed attributes
Typed attributes would fail the check.  Additionally, the error itself
was buggy, so fix that while we are at it.
2018-02-27 14:51:37 -05:00
Jarrod Johnson 9269c9feff Provide more reasonable error message to user
If a protocol is unsupported, propogate error message usefully.
2018-02-27 14:51:00 -05:00
Jarrod Johnson 7736056bf2 Fix hangtraces analyzer
With threadid, the analyzer was failing to collapse identical threads.
2018-02-27 11:28:37 -05:00
Jarrod Johnson 74e34f874c Merge remote-tracking branch 'upstream/master' 2018-02-26 15:49:54 -05:00
Jarrod Johnson 530c6553fd Block creation of nodes that can't be in noderanges
Noderange grammar prevents referencing certain nodenames.  Use the
noderange grammar to evaluate any incoming node or group at a very
low level.
2018-02-26 15:47:47 -05:00
Jarrod Johnson 2e3cd53ded Merge pull request #92 from aduffy19/nodeshellMan
Add [options] and -c description to nodeshell and nodemedia man
2018-02-23 15:46:00 -05:00
Amanda Duffy 4cc80f6c40 Add [options] and -c description to nodeshell and nodemedia man 2018-02-23 14:26:40 -05:00
Jarrod Johnson ff0ab4086a Merge pull request #91 from andywray/patch-2
Update nodemedia man page
2018-02-22 16:36:47 -05:00
andywray 337e8d6337 Update nodemedia man page
Fix bolding
2018-02-22 16:36:09 -05:00
Jarrod Johnson 1dd922c262 Merge pull request #90 from andywray/patch-1
Update nodemedia man page
2018-02-22 16:20:05 -05:00
andywray dae6f74acc Update nodemedia man page
Add (insecure) text
2018-02-22 16:19:21 -05:00
Jarrod Johnson 2323afc093 Merge pull request #89 from andywray/master
Fix nodemedia man page
2018-02-22 16:05:34 -05:00
andywray 9c9dffc385 Fix nodemedia man page
Put newlines in examples
2018-02-22 16:03:41 -05:00
Jarrod Johnson 62ac582b61 Provide better reseat error message on non-enclosure
If a user were to try to reseat a node that isn't enclosure based or
at least does not have the configuration, provide a clue as to what
happened.
2018-02-22 14:56:25 -05:00
Jarrod Johnson d473d23725 Add ability to specify attribs from environment
This is of particular use for passing passwords safely
into nodeattrib/nodegroupattrib.
2018-02-22 09:55:46 -05:00
Jarrod Johnson c5ce302717 Add usage back to nodefirmware
If the arguments are fruitless, provide a usage message rather than
blank.
2018-02-20 10:17:02 -05:00
Jarrod Johnson 22d79598b3 Fix erroneous parameter parsing
The change to add the selective nodefirmware queries incorrectly
mangled update.
2018-02-20 10:10:25 -05:00
Jarrod Johnson d7b3859460 Try to have collate preserve original noderange
When a noderange is given, prepare for a reverse lookup of same nodes,
so collate has a shot of giving back what was put in.
2018-02-14 15:09:21 -05:00
Jarrod Johnson 34f03cb217 Update nodefirmware man page 2018-02-14 14:56:45 -05:00
Jarrod Johnson 0fd2d26f82 Add access to nodefirmware shortcut
The nodefirmware can now request firmware more selectively.
2018-02-14 14:38:20 -05:00
Jarrod Johnson 453f6d8016 Catch general SSL errors to BMC
Provide better info on general SSL misbehaviors.
2018-02-13 13:17:29 -05:00
Jarrod Johnson ee84622e7d Dynamic retry timer
Opportunistically try to be more aggressive, scaling back
with retry number and cluster size.
2018-02-12 14:34:12 -05:00
Jarrod Johnson 2bfa890faf Actually enable ^=
It was inadvertently omitted.
2018-02-08 19:50:19 -05:00
Jarrod Johnson 94bce2f65b Unofficially tolerate pasu and own input
If someone tries to use this with pasu syntax, try to do the right
thing.  Similarly, if trying to paste the same syntax nodeconfig
uses on output, tolerate that as well.
2018-02-08 19:39:39 -05:00
Jarrod Johnson cc16aed27a Add ,= and ^= to group management
This greatly simplifies a common group membership task.
2018-02-08 19:30:06 -05:00
Jarrod Johnson 414572f626 Fix nodeattrib
nodeattrib was broken by the nodeconfig changes
2018-02-08 13:45:17 -05:00
Jarrod Johnson bac37dfa8d Update man page content
Provide documentation on the nodeconfig command, and fix a typo
2018-02-08 11:32:05 -05:00
Jarrod Johnson d3783aaa98 Change to shorter 'node' example
node or nodename are now acceptable, and {node} is less clumsy.
2018-02-08 11:18:48 -05:00
Jarrod Johnson 7dbdf2a6aa Add ability to exclude settings
This permits nodeconfig to prune out less interesting pieces of data
2018-02-07 15:46:08 -05:00
Jarrod Johnson d7322f013b Correct typo 2018-02-06 17:00:45 -05:00
Jarrod Johnson 024d37d633 Add support to show settings detail in nodeconfig
settings have lots of text, provide access through '-d' argument
2018-02-06 16:52:13 -05:00
Jarrod Johnson 8ef90a457a Add comparedefault to nodeconfig command
This allows gathering relevant settings that differ from default
2018-02-06 16:31:20 -05:00
Jarrod Johnson bd5d8c85d8 Add dependencies for the nodeconfig command to work 2018-02-06 08:59:06 -05:00
Jarrod Johnson 0afd9beeac Fix nodeconfig error handling
Additionally, make more strong effort to sort the data.
2018-02-05 15:23:13 -05:00
Jarrod Johnson b37ef7e90c Implement nodeconfig access to system settings
First draft
2018-02-02 17:17:02 -05:00
Jarrod Johnson 685f5c6803 Add system configuration
This gives access to system configuration where available
2018-02-02 16:20:13 -05:00
Jarrod Johnson 7f3763f9eb Clean up media error handling 2018-01-30 15:18:20 -05:00
Jarrod Johnson 290ccecfb9 Exit if requested upload file does not exist
It was fruitlessly sending to server, when it could detect the problem
up front without bothering the server.
2018-01-29 14:36:44 -05:00
Jarrod Johnson 0431e42452 Do not attempt to list after error
On upload/attach errors, do not bother to try to follow up with
list media, as the previous failure is more useful.
2018-01-29 14:21:38 -05:00
Jarrod Johnson 36e68ca852 Fix nodemedia list when errors are present
It would assume that databynode is always good news, but error data
can come as well.
2018-01-29 14:19:25 -05:00
Jarrod Johnson ba0e03d454 Provide a catchall for general certificate mismatch
Beyond the special partial cases for firmware/hardware inventory,
provide a catchall for invalid public keys and a message for it.
2018-01-29 14:17:01 -05:00
Jarrod Johnson e193e92fbf Make TLS errors in hardware/firmware more consistent
Also, place the error near the end where it is more likely to be
noticed, and close to where user would have expected the data to be.
2018-01-29 14:12:34 -05:00
Jarrod Johnson a7b0a449d6 Put ipmi errors in trace log
Put an end to the 'see stderr log'
2018-01-29 13:21:18 -05:00
Jarrod Johnson 2e7a8bee18 Fix nodemedia silent errors
For 'databynode' style responses, error data was suppressed.

Make printerror more thorough at handling such errors.
2018-01-29 11:21:46 -05:00
Jarrod Johnson 9e467c5e57 Add check for invalid dotted attribute names in expressions
This provides better feedback for typos and mistakes.
2018-01-26 17:00:03 -05:00
Jarrod Johnson 68d469788d Fix use of multi dot attributes in expressions
It was formerly only assuming ability to bisect, now recurse to get the
string out of nested attributes.
2018-01-26 14:29:22 -05:00
Jarrod Johnson 7ea99ecbf5 Improve expression error handling
First, refactor the attrname translation to be in a single method.

Recognize if 'None' comes back rather than a dictionary with na 'value'

Add a proper ValueError if an invalid attribute name is used.

Properly catch and transform ValueErrors in the API
2018-01-26 14:16:23 -05:00
Jarrod Johnson 49a444959d Add line wrap to usage error
It mixed output with next prompt, which is ugly
2018-01-24 13:42:13 -05:00
Jarrod Johnson 2628683881 Require minimum pyghmi
Many fixes we rely upon are only found in recent pyghmi.
2018-01-24 13:24:44 -05:00
Jarrod Johnson 1cf472470e Add warning if someone tries attach with a file
Rather than bother the server, sort out the problem locally.
2018-01-24 13:23:35 -05:00
Jarrod Johnson e7a70f390e Treat blank setting for gateway same as unset
It was previously trying to use empty string as gateway in some
contexts.
2018-01-24 10:55:03 -05:00
Jarrod Johnson 4ae32c1219 Merge branch 'master' of github.com:jjohnson42/confluent 2018-01-24 09:58:41 -05:00
Jarrod Johnson d04f6cc858 Accept '-f' as alias for '-c'
In xCAT, '-f' meant 'fanout' and it's harmless for us to support
both.
2018-01-24 09:26:18 -05:00
Jarrod Johnson 03703250e6 Further improve formatting of the discoverystate option 2018-01-23 16:28:07 -05:00
Jarrod Johnson 01dd48ccc2 Fix some man page formatting issues 2018-01-23 16:16:47 -05:00
Jarrod Johnson 91d0c8ed7a Add flag to request discovered devices by discovery state
Also refresh the manpage to reflect the current state of nodediscover
command, and flesh out the discovery states there.
2018-01-23 16:09:17 -05:00
Jarrod Johnson a2163244db Correct indentation 2018-01-23 15:19:31 -05:00
Jarrod Johnson f615232a95 Merge branch 'master' of github.com:jjohnson42/confluent 2018-01-23 15:05:33 -05:00
Jarrod Johnson e7aeece7f4 Add nodediscover clear
Provide means of deleting discovery data, particularly to help rescan.
2018-01-23 15:05:24 -05:00
Jarrod Johnson 19e733f325 Ensure fingerprint variable is initialized
During error handling, there were paths where fingerprint was
needed, but not set.  Fix this by getting fingerprint before raising
the exceptions.
2018-01-23 14:34:06 -05:00
Jarrod Johnson 924f679f79 Add ability to delete discovery entry
This allows a full purge without restarting confluent.
2018-01-23 13:27:20 -05:00
Jarrod Johnson 9baa1f5652 Accommodate XCC firmware behavior
It has been observed that a Lenovo XCC can fail to produce the
appropriate attributes in the SLP data.  In such a case, and only if we
are in the preconfig path (which means it is a candidate for discovery),
reset the XCC to try to correct the behavior.
2018-01-23 13:07:59 -05:00
Jarrod Johnson eccc7803a9 Move the (insecure) output to where promised 2018-01-23 10:36:25 -05:00
Jarrod Johnson cd260a769e Fix variable name
rsp rather than res was used in one place erroneously
2018-01-23 10:32:48 -05:00
Jarrod Johnson 56b6babed6 Provide insecure warning
When certificate validation is not occuring in a secure fashion, make
it obvious to user through '(insecure)' flag.  Lay the groundwork for
future update to actually provide a secure attach strategy, once the
firmware is willing.
2018-01-23 10:23:56 -05:00
Jarrod Johnson 37f0345553 Format the complex epilog of nodemedia
nodemedia has non-option arguments suggesting need for line wraps.
Provide a custom formatter to enable readable usage.
2018-01-22 16:12:29 -05:00
Jarrod Johnson 98a763eb35 Change detach to detachall
It is more clear what detach will do this way.  Also block more
attempts.
2018-01-22 15:56:59 -05:00
Jarrod Johnson 9b7db2a924 Explain the sort algorithm on collate
Provide a more thorough explanation of the sort algorithm
2018-01-22 15:09:19 -05:00
Jarrod Johnson 87696a7b0d Add man page for nodemedia
Documentation to flesh out the nodemedia command
2018-01-22 14:18:03 -05:00
Jarrod Johnson c2a15fc74d Fix typo in nodeconfig man page
The man page mispelled the command in the SYNOPSIS
2018-01-22 14:16:04 -05:00
Jarrod Johnson 97401e306b Tolerate disabled IPv4 multicast route
Sometimes the IPv4 multicast route isn't playing ball.  Tolerate such
a scenario and move on.
2018-01-22 11:53:19 -05:00
Jarrod Johnson 48b9d735f2 Avoid empty hwaddr
It has been observed, at least once, for an empty hwaddr to appear.
Take measures to prevent this from occurring and making into the
discovery info.
2018-01-19 10:22:22 -05:00
Jarrod Johnson 6444756b3c Add list to upload command
Have the upload command do list at the end to give affirmation of
what happened.
2018-01-17 10:06:54 -05:00
Jarrod Johnson af82e868d2 Alter nodemedia command
Add the glob protection and have attach do a list after.
2018-01-17 10:06:05 -05:00
Jarrod Johnson 76818135a6 Fix getting nodenames based on enclosure uuid
Must listify the output and make sure the previous output is fed into
the second filter.
2018-01-16 13:29:36 -05:00
Jarrod Johnson 0f4940cd7c Tolerate empty string to be blank snmp user
For SNMP password without user, accept '' as a synonym for None
2018-01-16 13:14:13 -05:00
Jarrod Johnson 8226c2bd77 Fix mistakes in the draft discovery code
A couple of blatantly obvious mistakes were made that require fixing.
2018-01-16 12:13:34 -05:00
Jarrod Johnson a80ae622f6 Skip SMMs without a stored certificate
If something happens to have the right ip, but no stored certificate
because it's not discovered, it was used as a data source if the
addpolicy was lax.  Harden the flow by skipping unverifiable parts
of the chain.
2018-01-16 10:54:42 -05:00
Jarrod Johnson ea5165d2c5 Fix the TLS verifier to support different fingerprint algos
It was hard baked to sha512.  Now use sha256 if auto-adding,
and use the stored algo as indicator instead.
2018-01-16 10:30:15 -05:00
Jarrod Johnson 30e24cc768 Fix type compatibility with enclosure.bay
enclosure.bay manifests as an int.  Use format() to tolerate either
way.
2018-01-16 10:20:28 -05:00
Jarrod Johnson b1951b3d86 Add error on older XCC firmware
When we do hit a problem with the chained configuration and older
XCC, log a message to show why discovery will forever fail.
2018-01-16 09:18:30 -05:00
Jarrod Johnson c649aa2a40 Avoid traceback on older XCC firmware
Older XCC firmware does not provide chassis-uuid.
2018-01-16 09:16:23 -05:00
Jarrod Johnson e7b97afc3c Address a number of oversights
The null handler case, IPv6 SMM, and SMM cert conversion needed fixes.
2018-01-11 16:48:34 -05:00
Jarrod Johnson 8acb59d967 Fix noderun/nodeshell filehandle exhaustion
noderun/nodeshell failed to close filehandles on child
exit.
2018-01-11 12:40:53 -05:00
Jarrod Johnson a70e3a2e19 Add ability for physical discovery to not root in switch
This permits a design where the switch can be omitted, but only the
head enclosure manager needs 'manual' intervention.
2018-01-11 10:46:23 -05:00
Jarrod Johnson a11a0cd543 Accelerate dependent discovery in D2 enclosures
Rather than wait until the next recheck interval, track and trigger
dependent discovery immediately.
2018-01-11 08:41:44 -05:00
Jarrod Johnson 3398acaf52 Match XCC to enclosure in a chained setup
Also apply fixes and lay groundwork for eventual 'secure' discovery
policy.  As such a policy is too limited to be practical at this point
(SMM only) the full deal is postponed until it would be feasible.
2018-01-10 15:53:49 -05:00
Jarrod Johnson 0c0a450fc2 Implement requisite functions to do chain SMM discovery
Hook into the neighbor data and lldp to identify SMMs.

Still need to provide context to the XCCs based on the chassis-uuid
property.
2018-01-09 17:25:31 -05:00
Jarrod Johnson 0337962cd9 Add lenovo-switch to discovery api
This does not actually allow config deployment, but it can help in
ascertaining access for manual access to a switch.

A proper 'handler' will come later to add configuration, probably with
an emphasis on CNOS rather than ENOS.
2018-01-09 09:17:39 -05:00
Jarrod Johnson 73f40ecbf8 Add a dir2img command to help with generation of RDOC
RDOC requires a valid 'floppy-like' image, this script aids in the
creation of such a thing.
2018-01-04 14:17:27 -05:00
Jarrod Johnson 9f5b88eb9f Fix nodemedia upload
Implement the tracking properly
2018-01-04 13:39:51 -05:00
Jarrod Johnson 3265d812ba Tweak the media implementation
Change key to 'detachall' for now and remove the 'all' argument from
detach.
2018-01-04 13:21:22 -05:00
Jarrod Johnson 673fb02896 Draft nodemedia command
Server side still has some limitations, but it functions when
going downhill with a tailwind while spewing error messages.
2018-01-03 15:35:08 -05:00
Jarrod Johnson 0d40a0cac6 Add ability to clear upload progress tracking
Remote media uploads could not be cleared, add the ability to do so.
2017-12-08 18:58:04 -05:00
Jarrod Johnson 6845f64d46 Correct spelling of tenant attribute
The attribute had been mispelled and needed a fix.
2017-12-08 18:42:08 -05:00
Jarrod Johnson ade1d93071 Fix strip_node on createdresource 2017-12-08 18:35:39 -05:00
Jarrod Johnson b18ad89672 Correct some errors in the previous commit 2017-12-08 18:27:35 -05:00
Jarrod Johnson 09d20ea1ff Add remote media handling to API 2017-12-08 15:03:27 -05:00
Jarrod Johnson ae39a84a30 Improved unrecognized memory format 2017-12-07 16:54:35 -05:00
Jarrod Johnson 0ae315a12f Fix bad SPD handling
If the memory is not DDR3/DDR4, cease further attempt to format
data.
2017-12-07 16:51:55 -05:00
Jarrod Johnson 60e8338b47 Fix logout
The logout was broken by the forwarder security hardening
2017-11-28 15:48:35 -05:00
Jarrod Johnson 8897eb5dcf Fix user api
The user api had been messed up.  Correct by using keyword to correctly
place the configmanager argument.
2017-11-28 15:23:27 -05:00
Jarrod Johnson 208eb46cc2 Merge branch 'master' of github.com:jjohnson42/confluent 2017-11-28 13:42:32 -05:00
Jarrod Johnson 2c5432454a Implement a nicer nodereseat unsupported command
This carries the error condition cleanly back to the command line.
2017-11-28 13:42:21 -05:00
Jarrod Johnson c5dd024557 Move the switch discoverable check for non-SMM into eval_node
eval_node can establish that this is a direct discovery attempt.
In that specific context, the check can be performed.  Otherwise,
we can't check in this way, but the enclosure manager should raise the
error on behalf of the rest of the situation.
2017-11-27 16:59:13 -05:00
Jarrod Johnson 72af8f1631 Fix custom and net.* attributes for groups and alias clearing
The _group function was not using fixup_attribute, add that.

Additionally, on the clear_ functions, use the aliases to make clearing
work with the shorthand as well.
2017-11-27 10:36:29 -05:00
Jarrod Johnson d69cca46d0 Rework check_globbing to reduce false positives
First, globbing can only be the cause of a mess up if the given
noderange is a file that matches.

With this we still have:
for node in $(nodelist compute); do nodepower $node; done
As a potential false positive if any node is a range.

For this, offer suggestion of changing directories.

Also, if it had been:
for NODE in $(nodelist compute); do export NODE; nodepower $NODE; done

Another clause can detect that, which has been added.
2017-11-27 10:04:23 -05:00
Jarrod Johnson 4bef5f7917 Merge branch 'master' of github.com:jjohnson42/confluent 2017-11-15 15:39:06 -05:00
Jarrod Johnson 03293d88b0 Have nodeeventlog print help on incorrect arguments 2017-11-15 15:38:59 -05:00
Jarrod Johnson b78266eff7 Merge branch 'master' of github.com:jjohnson42/confluent 2017-11-15 09:41:28 -05:00
Jarrod Johnson e63d7f9fe3 Correct typo in the nodeshell command
The November 6th change contained a typo.
2017-11-15 09:41:01 -05:00
Jarrod Johnson 16297b048f Add nodegroupdefine and nodegroupremove
With these, a user can noow largely ignore confetty for most
abosuletly universal functions.
2017-11-14 16:05:03 -05:00
Jarrod Johnson 6d88dbb374 Add missing man pages
Several commands did not yet have man pages, address this documentation
issue.
2017-11-14 15:55:03 -05:00
Jarrod Johnson 43c5ecd6ae Fix missing aliases 2017-11-14 15:16:58 -05:00
Jarrod Johnson 9d2ec60b50 Set executable bits on various commands 2017-11-14 14:59:37 -05:00
Jarrod Johnson a16d4b12ea Merge branch 'master' of github.com:jjohnson42/confluent 2017-11-14 14:29:57 -05:00
Jarrod Johnson 76bfb29d60 Try to put the brakes on too many mac discovery attempts
In various scenarios, too many macs on a port can be a sign of trouble.
For example, a chained SMM configuration with head on switch port, or
incorrectly pointing a nodes net attributes at a switch uplink port, or
defining SMMs without any nodes, causing XCCs to think they are
rackmount.  This sets some sanity value for avoiding problems.  This is
of course a mitigation, invalid scenarios could still run afoul of the
limits, but it should catch a large chunk of offending scenarios.
2017-11-14 14:28:31 -05:00
Jarrod Johnson 3e201a5f4f Back off aborted use of configmanager in nodegroups
Currently, we don't need it and the change was half-attempted.  Remove
the problematic half that remained.
2017-11-14 12:01:57 -05:00
Jarrod Johnson 0b0f325240 Shorten power check interval
The interval can be shorter with little ill-effect.
2017-11-13 14:22:30 -05:00
Jarrod Johnson 29330aee74 Clear [powered off] from screen if state change detected
Previously, only transition to powered on was detected.  React
to situations where data comes up or power status change.
2017-11-13 14:04:09 -05:00
Jarrod Johnson 78dea26d06 Switch glob suppression to detection
The suppression was unable to be accomplished for bash without
somehow otherwise breaking the shell.  zsh and csh could be better at
one-off glob disabling though.
2017-11-13 11:49:40 -05:00
Jarrod Johnson a00747c79c Update nodeconsole man page 2017-11-10 10:37:48 -05:00
Jarrod Johnson 4bbc05699e Fixed log age out with size and time rolling
There was a problem if both size and time based age out were triggering
and failing to honor backupCount.
2017-11-10 08:48:36 -05:00
Jarrod Johnson 06eb91c355 Fix formatting of nodediscover synopsis
Markdown's annoying use of trailing whitespace strikes again.
2017-11-09 16:47:49 -05:00
Jarrod Johnson 5b52582302 Merge branch 'master' of github.com:jjohnson42/confluent 2017-11-09 16:31:29 -05:00
Jarrod Johnson 4de797be05 Add man page for nodediscover 2017-11-09 16:31:11 -05:00
Jarrod Johnson 80864d78b3 Remove unused nestedmode
Without the ability to reliably tell a nodename from an input key,
must not do the nestedmode detection.
2017-11-08 13:36:36 -05:00
Jarrod Johnson cc4950ef75 Opportunistically grab and sort by node
If output comes close enough together, make some effort to group it
so that it will have a higher tendency of looking orderly.  This of
course only does so when it does not interfere with quickly presenting
the data.
2017-11-06 15:47:59 -05:00
Jarrod Johnson fcae11bf96 Do natural sort on expression expansion
This creates more logical behavior from nodeshell and noderun when
dealing with many nodes, particularly when crossing the concurrency
limit.
2017-11-06 14:57:15 -05:00
Jarrod Johnson f5889e7029 Add '-c' to manage noderun/nodeshell concurrency
Allow user to specify custom parallel count.
2017-11-06 14:51:59 -05:00
Jarrod Johnson 148329dd8e Implement send resize commands
Craft correct stty commands based on terminal size
detected by confluent.
2017-11-06 11:09:55 -05:00
Jarrod Johnson d9ffa10422 Restore power query function
Implement it in a fashion that does not block confetty while long
running power query situations happen.
2017-11-06 10:24:32 -05:00
Jarrod Johnson a6bae944a2 Explicit dependency version in rpm
Installs without update can end up with non-viable old versions.

Force yum to try to update downlevel packages if present.
2017-11-06 09:20:12 -05:00
Jarrod Johnson 65bcb8a35b Add glob supressing aliases for new commands
Also, document what they are for the curious.
2017-11-03 16:59:27 -04:00
Jarrod Johnson 31a2fce521 Add noderemove command
Easy deletion of nodes from the confluent database.
2017-11-03 16:54:07 -04:00
Jarrod Johnson ea49108c78 Add nodedefine command
Provide a quick command to define new nodes to confluent direct
from cli without confetty.
2017-11-03 16:39:46 -04:00
Jarrod Johnson 21fce4098b Add ability to list all configuration supported 2017-11-03 10:36:32 -04:00
Jarrod Johnson 8eca6b156b Automatically request static when setting ip
If someone is setting IP address, they are implying static.
Change that implicit reality to explicit statement.
2017-11-03 10:31:00 -04:00
Jarrod Johnson 7f4ea287bc Fix issues in expression enabled InputNetworkConfiguration
This enables setting using expressions for any network configuration
functionality.
2017-11-03 10:25:26 -04:00
Jarrod Johnson 9f3fe01a49 Evolve the concept, it does not currently work 2017-11-02 17:07:44 -04:00
Jarrod Johnson de6ecdab38 Start work on nodeconfig command
This reworks the client to reuse some bits of nodeattrib, and has
nodeconfig able to read values.
2017-11-01 16:48:17 -04:00
Jarrod Johnson 02018da187 Add aliases to the client library
Replicate for the sake of retrieving values by aliased names.
2017-11-01 13:33:57 -04:00
Jarrod Johnson 8bc766e740 Add concept of aliases for setting and expressions
For the moment this allows some shortcuts on setting and
expressions for {bmc}.  Other attribute aliases may come.
2017-11-01 13:28:46 -04:00
Jarrod Johnson 8c21c59459 Dynamic backoff for switch scan
Have switch scan back off propritonate to time it takes to walk the
switches.  Avoid being back to back on switch scans.
2017-10-27 16:50:39 -04:00
Jarrod Johnson d5be1ccf8c Restrict lifetime of port relay to session
If a session is closed, also kill off any associated
relays in progress.  One exception, video port relay
in ESTABLISHED is left alone due to limitation, but
at least no new open.
2017-10-27 14:47:10 -04:00
Jarrod Johnson 45b8a18f14 Merge branch 'master' of github.com:jjohnson42/confluent 2017-10-26 13:31:36 -04:00
Jarrod Johnson d502cd5159 Add nodereseat command to confluent command 2017-10-26 11:48:42 -04:00
Jarrod Johnson 52673a990b Confluent server side enclosure reseat
This provides ability to request reseat of nodes, and redirects it to
the enclosure manager.
2017-10-26 11:45:16 -04:00
Jarrod Johnson 43c60bc180 Add another invalid uuid
This is another uuid that will not be unique that may appear in some
systems without a valid uuid.
2017-10-25 16:16:00 -04:00
Jarrod Johnson c86d9f3e33 More specifically restrict connectivity
When serving multiple browser, limit a forwarder to only the specific
client that authorized that forwarder.  Previously, one client was
allowed to access another client's forwarding port if it happened to
know the location.
2017-10-23 09:34:29 -04:00
Jarrod Johnson 68221b8158 Provide distinct video forwarding per client ip
While we are limited to one 'listen' target at a time, we can
qualiify by the source address to at least provide distinct
behavior depending on the client.
2017-10-23 09:28:24 -04:00
Jarrod Johnson 34fb159801 Restrict forward source ip to requestor
This prevents sockets from opening up to the world that could be used
to connect to management interfaces directly, apart from the specific
requestors.
2017-10-22 12:35:12 -04:00
Jarrod Johnson 3372a8401a Move registration of key handler up to constructor
This should be a more bulletproof place to be.  Note that it used
to be here and was moved because pyghmi used to call oem_init, but
pyghmi has been changed for a long time to no longer have that
requirement.
2017-10-20 15:18:03 -04:00
Jarrod Johnson f07a0e333f Use natural sort in parts of macmap api
It was hard to traverse things through default sort, provide
natural sort to node names and port names.
2017-10-20 15:15:59 -04:00
Jarrod Johnson 301014f3b5 Fix nodediscover rescan
Actually request that the server do rescan, rather than queueing it up
and failing to transmit.
2017-10-20 13:53:13 -04:00
Jarrod Johnson aa0255bf62 Limit firmware updates to 256 at a time
To keep the concurrent update level to a fairly widely attainable limit,
impose 256 at a time limit.  This is a gigantic improvement over most
previous circumstances still, and can comfortably accommodate three of
the most dense racks at a time.
2017-10-20 08:43:43 -04:00
Jarrod Johnson 444ba917eb Have node*attrib commands error if user does -c and =
Can't clear and assign in one go, error for user awareness.
2017-10-19 10:02:30 -04:00
Jarrod Johnson 6659b31106 Provide graceful error message on cert mismatch
Firmware update can provide a more clean looking message on the
event of a cert mismatch.  Improve polish by doing it this way.
2017-10-18 12:58:21 -04:00
Jarrod Johnson 3e93cb2434 Stub out strip_node for DeletedResource
This is only ever a URL at the moment.  Do not trigger stack
traces in firmware update by stubbing out the strip_node.
2017-10-18 10:58:17 -04:00
Jarrod Johnson ffaabd5ae3 Do not process incomplete DIMM info
A malformed SPD given by BMC is now presented as Unrecognized,
rather than trying to format data that does not exist.
2017-10-18 09:51:31 -04:00
Jarrod Johnson d26f6259a7 Add explicit error about certificate mismatch
Before we were aborting without info.  Now explain the missing
information by including the error explaining why it is missing.
2017-10-17 13:46:40 -04:00
Jarrod Johnson 757df0f571 Reduce noise of one off reading
Per request, limit the display precision of floats in the nodesensors
command readout.
2017-10-17 11:32:17 -04:00
Jarrod Johnson bfc2b65e99 Support 'energy' sensor category
Energy is distinct from power, categorize it as such.
2017-10-17 11:07:54 -04:00
Jarrod Johnson 3a1e9fe0bc Fix typo in function name 2017-10-16 11:21:18 -04:00
Jarrod Johnson bb03e4a961 Fix HTML view for simple string values
Simple string values were incorrectly treated in the HTML view.
Fix it so the data is actually readable.
2017-10-16 10:38:13 -04:00
Jarrod Johnson f7b5280d6a Fix HTML view with bool value
HTML view was causing internal server errors when the api provided
boolean data
2017-10-16 10:35:47 -04:00
Jarrod Johnson f1f6c3b066 Correct syntax error
The prior commit had a grave syntax error.
2017-10-16 10:30:02 -04:00
Jarrod Johnson b7b26a1069 Merge branch 'master' of github.com:jjohnson42/confluent 2017-10-16 10:21:15 -04:00
Jarrod Johnson e3b869fa34 Fix minor formatting issue 2017-10-16 10:21:01 -04:00
Jarrod Johnson a962a5afc3 Exempt Web Forwarding from CSRF
Web forward from popup context requires it be exempt from CSRF
protection.  This is harmless (as all GET should be, but erring on side
of caution), so add it to the whitelist of CSRF skipping on a CSRF
enabled client session.
2017-10-16 10:20:49 -04:00
Jarrod Johnson b2fdaeffe7 Add 'Power' to relevant categories for power
While IPMI has no 'Power', some OEM sensors use that
type anyway.
2017-10-13 16:08:59 -04:00
Jarrod Johnson 8694eca40b Error out a whole noderange if global error occurs
For example, nodeboot with invalid argument failed and then proceeded
to 'boot' phase.
2017-10-13 09:08:12 -04:00
Jarrod Johnson d5efa87288 Add history to the dbg cli helper
As long as we are adding readline, history persistence is also really
handy.
2017-10-12 14:15:36 -04:00
Jarrod Johnson 6a39a3f9a2 Fix html api browser add/assign resource
The html extraction was unable to process the message.
2017-10-10 09:16:06 -04:00
Jarrod Johnson 9b1e70893b Merge branch 'master' of github.com:jjohnson42/confluent 2017-10-10 09:13:21 -04:00
Jarrod Johnson 672c127621 Fix error propogation on manual discovery
Manual discovery needs to give the user, not the log info about the
failure.
2017-10-06 16:10:47 -04:00
Jarrod Johnson 158a9705db Support full assign from csv input 2017-10-06 14:34:34 -04:00
Jarrod Johnson e7c6dfab2b Fix list by invalid type
Rather than list everything, list nothing
when asked to list an invalid type.
2017-10-06 14:02:49 -04:00
Jarrod Johnson c891cff926 Phase 1 of bulk assignment
Parse CSV and do some validation, next phase will actually
create nodes and assign the discovery.
2017-10-05 16:55:11 -04:00
Jarrod Johnson a8a32118db Add the ability to assign
Start with the ability to assign one at a time.
2017-10-05 13:52:20 -04:00
Jarrod Johnson fdc4e959f7 Populate nodename on pxe entries when possible
If a PXE is matched by UUID, populate the nodename just like the
serial number and such.
2017-10-05 10:16:49 -04:00
Jarrod Johnson 91ff08158f Add rescan subcommand to nodediscover
Allow nodediscover to initiate an active scan.
2017-10-05 10:05:56 -04:00
Jarrod Johnson 79b47bd0b7 Create nodediscover command
Provide a command to interact with discovery data in a more convenient
way.  This commit comprises at least most of the ability to list and
filter.
2017-10-04 16:27:40 -04:00
Jarrod Johnson c95d3cf906 Note for future chassis id relationship 2017-10-04 09:43:35 -04:00
Jarrod Johnson 9c6b10a166 Sort output from confetty
Sorting can greatly improve the readability of some
confluent functionality.
2017-10-04 09:09:03 -04:00
Jarrod Johnson db89cdc62c Add portid and chassisid for cross-reference
In the hypothetical of generating a graph, having a hard assurance
of the required LLDP TLVs can aid in viable code.
2017-10-03 14:57:32 -04:00
Jarrod Johnson 697716b296 Provide a cleaner error on peer not found
Auto-refresh and provide cleaner error on ultimately missing data.
2017-10-03 11:52:28 -04:00
Jarrod Johnson 60b7083dce Handle URL safety of LLDP data
LLDP data does not care about URL safety.  Have a mechanism that
does a pretty good job of translating too and from, at some cost.
2017-10-03 11:23:57 -04:00
Jarrod Johnson f4cfe8758e Fixes to the recent attempt
Names had '/' in it and some assumptions about key were broken.  Correct
the various mistakes.
2017-10-03 10:30:18 -04:00
Jarrod Johnson cc0fc52064 Reuse neighbor data
Improve responsiveness by only refetching data if the data is over
a minute old.
2017-10-03 10:01:57 -04:00
Jarrod Johnson 526eb45969 Fix to match all critera than any.
It was matching *any* of the criteria, it needed to match all.
2017-10-02 17:04:38 -04:00
Jarrod Johnson 3606aab3f0 Only director-ify multiple entry type selectors 2017-10-02 17:01:43 -04:00
Jarrod Johnson eb70b21573 Properly reflect results as collections/directories 2017-10-02 16:56:52 -04:00
Jarrod Johnson e95b5da8b7 Wire up peerid
The entries did not have peerid in them, rectify the oversight.
2017-10-02 16:56:17 -04:00
Jarrod Johnson b5e4d302f9 Actually wire up the parameterized version 2017-10-02 16:53:27 -04:00
Jarrod Johnson 1fb6eb230b Change mind about peerid
Stick to the identifiers mandated by LLDP, and only those to
base the peerid (by-name can help otherwise).
2017-10-02 13:32:56 -04:00
Jarrod Johnson e298ead944 Merge branch 'master' into betterneighbor 2017-10-02 13:28:33 -04:00
Jarrod Johnson c0ab8532df Fix noderun when invalid noderange passed
exitcode was not yet set when starting to be referenced.  Initialize to
zero prior to any possible reference to fix.
2017-10-02 09:07:06 -04:00
Jarrod Johnson 4e1ebc290b Fix noderun when invalid noderange passed
exitcode was not yet set when starting to be referenced.  Initialize to
zero prior to any possible reference to fix.
2017-10-02 09:06:29 -04:00
Jarrod Johnson 4236f3fd78 Work on a better neighbor interface
The API was lacking in imagination, flesh it out more.
2017-09-28 17:09:05 -04:00
Jarrod Johnson d4265fa406 Normalize likely HEX strings
Chassis Id and Port Id are highly likely to present as hex strings,
detect and present this case more sanely.
2017-09-28 16:28:33 -04:00
Jarrod Johnson 563ee96879 Harden confetty to weird text strings
If it can't properly encode to printable, use repr instead.
2017-09-28 16:20:19 -04:00
Jarrod Johnson 529e3b2239 Fix a few issues found in testing
Switches need some data sanitized.  Also used IndexError instead of
KeyError, and add handling for interfaces with slashes in the name.
The name 'verified' also fits better than 'authenticated'
2017-09-28 14:27:34 -04:00
Jarrod Johnson 2ed80d86b1 Implement proper neighbor structure
Also fix a bug in macmap and assume SHA auth protocol for SNMPv3
2017-09-27 15:03:09 -04:00
Jarrod Johnson 317809f449 Further refactor and mature neighbor data
At this point, the /networknig/neighbors mostly works...
2017-09-27 14:24:00 -04:00
Jarrod Johnson ea27125587 Begin implementing the 'neighbors' collection
Refactor some common function and list interfaces on a switch
2017-09-26 16:56:45 -04:00
Jarrod Johnson 0741e3953e List switches if known even without macs
The macs was only showing switches with currently known mac address.
Provide all the data (and perhaps a hook to geet errors later).
2017-09-26 12:13:01 -04:00
Jarrod Johnson f44eb412c5 Add /nodes/<node>/forward/web
This facilitates GUI to launch web interface,
even if the target is unreachable.
2017-09-22 13:53:37 -04:00
Jarrod Johnson c571601a29 Add utility library to do port forwarding
This will be useful for creating forwarding for
users.
2017-09-22 10:59:37 -04:00
Jarrod Johnson dad86242a9 Performance optimize abbreviation
Don't abbreviate the same nodes twice when we don't have to.
2017-09-22 10:06:02 -04:00
Jarrod Johnson a0802dd66e Add natural sort
For output groups with equivalent node counts, sort naturally
by the group text header.
2017-09-22 09:54:28 -04:00
Jarrod Johnson c966b09581 Fix behavior on firmware update timeout
nodefirmware was not handling results where the update couldn't even
start.  Handle those errors properly.
2017-09-22 09:32:43 -04:00
Jarrod Johnson b631699656 Correct incorrect bank parameter on nodefirmware -b
The bank should have been 'backup', not 'bank' which makes no sense.
2017-09-22 09:06:42 -04:00
Jarrod Johnson aa6857b1c7 Do not consider refusal of default creds fatal
During discovery, there's a chance that user/pass already set.
For now, do not fret over this and just silently fail to enable
enclosure manager.
2017-09-19 15:22:40 -04:00
Jarrod Johnson 9c5f50341f Various fixes to the previous attempt 2017-09-18 14:51:43 -04:00
Jarrod Johnson eb1b80f2c9 Get UUID from enclosure and set
During config, take the opportunity to update uuid for enclosure.manager
if possible.
2017-09-15 17:00:36 -04:00
Jarrod Johnson 368666823f Modify get_nodename to search by uuid
Instead of *just* being able to search by uuid for pxe,
add the ability to search by uuid for https things, if no fingerprint
match.

This allows remote xcc setup to follow in the wake of a pxe attempt.
2017-09-15 12:00:10 -04:00
Jarrod Johnson d8216f2472 Add another invalid UUID
All spaces is yet another bad UUID that has cropped up...
2017-09-15 11:14:00 -04:00
Jarrod Johnson 0db2e1cea6 Add clarification on what noderange is for 2017-09-12 15:29:59 -04:00
Jarrod Johnson 6a1f7e7fa4 Fix for incorrect uuid format
In the slp data, the data is an array, make it a string first.
2017-09-11 16:42:56 -04:00
Jarrod Johnson e2e4c8c7e1 Add SMM UUID to info when available 2017-09-11 15:21:55 -04:00
Jarrod Johnson ee7e044ad8 Add missing socket import
The Non-sysfs fallback needs to have socket imported to function
2017-09-05 11:20:42 -04:00
Jarrod Johnson 12cbfff24f Fix for unexpected entries in /sys/class/net
For example, in a bonding configuration there is a file there, not just
directories with ifindex entries.
2017-09-05 09:19:15 -04:00
Jarrod Johnson 8774ae0305 Avoid linking obviously bad UUIDs
If UUID is obviously bad, do more to ignore it when linking data
2017-08-26 23:20:45 -04:00
Jarrod Johnson cb00c5d35d Place limits on discovery resource consumption
Situation of filehandle exhaustion was seen.  In the scenario observed,
multiple connections to the same target were seen.  So:

1) Backout the recheck block and replace with more comprehensively
placed semaphore.

2) Place a discovery pool limit of 500 to generally constrain things.

3) Further limit things to one detected thread per mac address
2017-08-26 22:45:36 -04:00
Jarrod Johnson 2a0b038c30 Merge pull request #83 from aduffy19/noderange
Add noderange man page
2017-08-25 16:42:12 -04:00
Jarrod Johnson deb2c3a94a Correct some minor potential issues and add restart on failure 2017-08-25 16:41:22 -04:00
Amanda Duffy 3f1bb1c151 Add noderange man page 2017-08-25 16:39:07 -04:00
Jarrod Johnson 0e708f4b26 Back off https recheck
With various fixes, it does not make as much sense to be so aggressive
with rechecking https assuming we sense something prior to https
being up.
2017-08-25 09:24:21 -04:00
Jarrod Johnson 5c93976bdb Fix errant certificate handling
Non-replacement detection was being treated as replacement.  Correct
that mistake.
2017-08-24 16:57:06 -04:00
Jarrod Johnson 312af72d9f Fix policy handling if not set 2017-08-24 16:34:57 -04:00
Jarrod Johnson 19f75474fc Fix db restore reliability if replacing existing
If there is an existing DB, there were race conditions in loading the
restore.  Fix by clearing the existing DB once the viability of the
restore dataset has been established
2017-08-24 16:04:04 -04:00
Jarrod Johnson 695e038ced Skip attempt to fixup custom attributes 2017-08-24 16:01:00 -04:00
Jarrod Johnson a98d8dc43c Provide capture of PXE mac addresses to net*.hwaddr
This provides a persistent store of PXE mac addresses for consumption
by other provisioning systems that are generally MAC centric.
2017-08-24 15:42:40 -04:00
Jarrod Johnson 69cbeecf1b Correct fixup for untyped data 2017-08-24 13:44:21 -04:00
Jarrod Johnson 5cd461c6ad Add understanding of net.* attributes to fixup
net.* are special, add them to the fxup so that the bootable attribute
is correctly amended.
2017-08-24 13:26:38 -04:00
Jarrod Johnson de30c53d21 Add net.*.bootable
Provide a flag to indicate that a nic entry is meant to hold
a bootable network interface, for purpose of holding a PXE detected
mac.
2017-08-24 13:15:32 -04:00
Jarrod Johnson a599c346f8 Add support for boolean attributes
Normalize likely textual input to a boolean, but otherwise treat such
data in the same manner as a string.
2017-08-24 13:14:23 -04:00
Jarrod Johnson 1e88ce2d41 Flesh out pxe client info if matching discovery data found
While we cannot get serial number and model number in a PXE request,
if there is a matching uuid, fill in the data from the match.  Also
provide info on the related macs so that info can be correlated in more
complex ways (e.g. which mac is pxe, which mac is BMC, which IP goes
where, etc.)
2017-08-24 10:23:43 -04:00
Jarrod Johnson d337de671e Add missing uuid list generator link
The UUID mapping was not connected fully to the API.
2017-08-23 15:52:20 -04:00
Jarrod Johnson 68c7ab4c90 Add ability to group discovery by uuid
API adds 'by-uuid', which helps group BMC and PXE together to make
relationship clear.
2017-08-23 15:41:16 -04:00
Jarrod Johnson 4af5e2d615 Correct uuid retrieval mistake 2017-08-23 13:17:18 -04:00
Jarrod Johnson 299c5c4e71 Add UUID to returned discovery data when available 2017-08-23 12:57:34 -04:00
Jarrod Johnson e5c330bb1c Be less verbose about non-viable data in periodic recheck
If we have a device that has aged out of usable addresses, do not pester
log about this incessantly.
2017-08-23 12:47:44 -04:00
Jarrod Johnson e1eafa46f9 Be robust in handler init withotu addresses set 2017-08-23 11:16:07 -04:00
Jarrod Johnson 9798f30ef8 Remove codecs getwriter unicode from nodesensors
In nodesensors, things are made into binary strings explicitly,
which causes the codecs.getwriter to choke
2017-08-22 16:54:25 -04:00
Jarrod Johnson d1bafa98bb Merge branch 'master' of github.com:jjohnson42/confluent 2017-08-22 16:50:20 -04:00
Jarrod Johnson 2cdfa8fcae Do not let a single node error stop all pending node
Isolate faults to single node for better robust behavior.
2017-08-22 16:50:04 -04:00
Jarrod Johnson b93a2e60d2 Be more selective in IP pruning
Only prune known bad IPs, not the whole list
2017-08-22 16:47:56 -04:00
Jarrod Johnson e478f8aef3 Add --backup to nodefirmware man page 2017-08-16 17:38:52 -04:00
Jarrod Johnson b35463e594 Implement argument to nodefirmware to backup 2017-08-16 17:33:23 -04:00
Jarrod Johnson 54f25cfa9e Implement access to other banks
Provide backend support for other banks than primary.
2017-08-16 17:30:18 -04:00
Jarrod Johnson 9ff7829373 Fix typo in confetty
Strings do not have a startswitch method...
2017-08-16 15:06:48 -04:00
Jarrod Johnson f3b56cf187 Add abbreviate to man page
abbreviate was not in the man page for collate.
2017-08-16 11:34:36 -04:00
Jarrod Johnson 783837b9be Further collate page formatting fixes 2017-08-16 10:42:44 -04:00
Jarrod Johnson 1b18edcccb Fix formatting issues in collate man page 2017-08-16 10:31:58 -04:00
Jarrod Johnson d972e2c12c Fix man page for section 1 2017-08-16 10:12:03 -04:00
Jarrod Johnson c5cf829117 Avoid stacktrace on pipe on non-ascii
Various commands may (accidentally or intentionally) encounter
non-ascii data.  While python stdout without pipe is fine, when piping
it assumes ascii.  Fix this to always assume utf-8 explicitly.
2017-08-16 09:57:57 -04:00
Jarrod Johnson 2f55a251cd Provide more graceful behavior when input has no ': '
Rather than do a stacktrace, place such data into an 'UNKNOWN' output
group, like xcoll did.
2017-08-16 09:44:22 -04:00
Jarrod Johnson d63f6ec9f0 Fix install of collate man page 2017-08-16 09:42:30 -04:00
Jarrod Johnson 9d582262e6 Update man page information
Document use of collate and firmware update
2017-08-15 16:17:28 -04:00
Jarrod Johnson 2063436ccc Reduce context of collate diff
diff mode is less useful with superfluous context.
Suppress context to focus more on differences.
2017-08-15 16:11:38 -04:00
Jarrod Johnson 6addd05de2 Stop firmware when 'pending', which is another 'completion' 2017-08-14 17:10:42 -04:00
Jarrod Johnson 28259511ed Add abbreviate to collate
Also, perform natural sort on 'nodenames' when not abbreviating
2017-08-14 15:06:57 -04:00
Jarrod Johnson 0393e55eb1 Implement API for reverse noderange
Provide reverse noderange through special
/noderange//abbreviate location.  This should enable
collate to abbreviate noderanges.
2017-08-14 14:41:43 -04:00
Jarrod Johnson f7b964b2ce Implement feedback on final state of firmware
Some things on update are active immediately, others are pending reboot.
Documentation needs to use this to let users know what they need to do
or not need to do after the firmware update.
2017-08-14 10:04:19 -04:00
Jarrod Johnson da0941c229 Suppress noise of sysctl command 2017-08-11 16:37:09 -04:00
Jarrod Johnson 7cec311b22 Fix sysctl packaging info 2017-08-11 16:11:05 -04:00
Jarrod Johnson 8ada0e7cf4 Read in sysctl tune on install
This ensures that the value is ready for slp plugin
2017-08-11 15:45:56 -04:00
Jarrod Johnson 87e2e481c2 Tune the UDP receive buffer
We have a sysctl tune file and option to
go higher so that we get more SLP responses.
2017-08-11 15:43:44 -04:00
Jarrod Johnson 38546514e2 Pull UUID into info for rackmount
UUID was erroneously not pulled.  The block on dense/blade should
only apply to enclosure bay.
2017-08-11 10:07:42 -04:00
Jarrod Johnson 1e54abd29b Implement reverse noderange
This is the library feature.  A remote API call will be addded
so that the likes of collate can use it.
2017-08-10 16:45:38 -04:00
Jarrod Johnson a571faa215 Implement collate command
Also adjust output to be less buffered for sake of '-w' and other
pipe commands.
2017-08-09 17:08:52 -04:00
Jarrod Johnson 87da7b62ae Correct mistake in the model attribute name
The info calls it 'modelnumber' rather than 'model'
2017-08-09 14:55:27 -04:00
Jarrod Johnson 8d02d7cc7f Store serial and model number in id attributes on discovery 2017-08-09 14:31:29 -04:00
Jarrod Johnson 5f1f41b975 Add serial and model number to the id attributes
Lay groundwork for pulling this sort of data in on discovery.  The plan is that *if* serial numbers will
be used as a cue for discovery, it would be in the context of a nodediscover command.
2017-08-08 15:51:27 -04:00
Jarrod Johnson 7c1bbe1618 Fix error in the usage text of nodeinventory 2017-08-08 15:45:53 -04:00
Jarrod Johnson 76e6f2dd17 Update online usage message for nodeinventory 2017-08-08 11:56:06 -04:00
Jarrod Johnson 67f2282cc4 Update nodeinventory page with new usage info 2017-08-08 11:55:31 -04:00
Jarrod Johnson b98eea81ad Add filtering to nodeinventory
Allow filtering output by various parameters.
2017-08-08 11:49:50 -04:00
Jarrod Johnson 3bf84ee1e7 Merge branch 'master' of github.com:jjohnson42/confluent 2017-08-08 10:39:49 -04:00
Jarrod Johnson 498803f70a Fix line wrap in nodebmcreset example
Again, the curious behavior of markdown for line break
to be two spaces at the end bites some documentation.
2017-08-08 08:36:21 -04:00
Jarrod Johnson 9ac7158bdd Fix SMM enablement on XCC in SD530
The form factor is, at least in one test, an array, not a string.  Just in case, tolerate
either way.
2017-08-07 13:46:14 -04:00
Jarrod Johnson 4110d18f43 Fix exitcode init in noderun
The order was incorrect in the code.
2017-08-07 11:42:58 -04:00
Jarrod Johnson efe3db11ce Add trigger for restarting on pyghmi updates
Often times, a pyghmi update carries the substance of
a patch.  Instead of a person having to remember to
manually restart, try to trigger an update to restart
confluent automatically.
2017-08-07 09:51:04 -04:00
Jarrod Johnson c8fbb58ae9 Correct overzealous deletion
Selection error caused if statement to have syntax error.
2017-08-03 09:41:21 -04:00
Jarrod Johnson 05715c6826 Fix noderun in same way as nodeshell
noderun had a similar issue about error handling.
2017-08-03 08:40:58 -04:00
Jarrod Johnson 5d7df6dceb Fix error handling in nodeshell
nodeshell needed to process errors correctly, and not assume databynode would be there.
2017-08-03 08:39:04 -04:00
Jarrod Johnson dbcc33629a Fix nodeshell overeager parsing
In the case of execing to ssh, preserve literal argumants since
ssh is going to parse them.  Pre-parsing will cause ssh to strip out spaces, for example.
2017-08-03 08:33:29 -04:00
Jarrod Johnson 085a9fed37 Do not error if debug or usr1 handling is impossible
Windows is a limited platform, let it run regardless.
2017-08-02 16:43:08 -04:00
Jarrod Johnson 659c4e4217 Avoid trace on deleted node
If a node is deleted, act similar to if it were defined with no console.method, to avoid
superfluous trace output.  In the future, it may make sense to filter out nodes with no
console.method earlier, since a fair amount of startup work is done that is ultimately ignored
for situations where console is not enabled.
2017-08-02 10:00:16 -04:00
Jarrod Johnson 28ba40ccfa Replace SOL locknig with NullLock
Again, eventlet monkeypatching of pyghmi seems to be messing up
use of RLocks...
2017-07-31 10:05:50 -04:00
Jarrod Johnson e2b7440a5c Put id of thread in the trace
When looking at the traces, handy to have ids for each thread for various
purposes.
2017-07-31 10:02:05 -04:00
Jarrod Johnson a55ba02d11 Merge remote-tracking branch 'upstream/master' 2017-07-28 16:05:45 -04:00
Jarrod Johnson 2ef549c2ae Correct the NullLock
NullLock was not what util.protect was expecting, provide more function calls, all of which do nothing.
2017-07-28 16:05:10 -04:00
Jarrod Johnson 8123a77451 Merge branch 'master' of github.com:jjohnson42/confluent 2017-07-28 15:53:25 -04:00
Jarrod Johnson 9e44087047 Breakup logentries exceeding 65k
The data length of a log entry must not exceed 65k.  If an attempt is
made to log that much, break it up and duplicate the records.  It may make
sense to indicate a continuation explicitly, but for now just extend.
2017-07-28 15:53:07 -04:00
Jarrod Johnson 6e51e02e1b Merge pull request #81 from aduffy19/nodebmcreset
Nodebmcreset
2017-07-27 15:03:08 -04:00
Amanda Duffy 3e90dd6462 Pass sys.exit() an argument
Change sys.exit() to sys.exit(success)
2017-07-27 14:31:37 -04:00
Jarrod Johnson 4a929eb9b5 Merge branch 'master' of github.com:jjohnson42/confluent 2017-07-27 09:03:53 -04:00
Jarrod Johnson 858647bb6d Change to str for exception message
str will tend to present a more normal looking error string.  Use
that so that a user does not have the impression there is a code
issue on expected errors.
2017-07-27 09:03:36 -04:00
Jarrod Johnson 8a416ccc5e Correct mistake in core formatting 2017-07-26 16:57:06 -04:00
Jarrod Johnson 12d0fe21cd Only show error message when errors exist 2017-07-26 16:37:09 -04:00
Jarrod Johnson 7a88a2825d Add 'update' to nodefirmware
nodefirmware can now execute updates on a file by file basis.
2017-07-26 15:54:21 -04:00
Jarrod Johnson bc9a498683 Provide a library for compact text node data
Some processes (e.g. nodefirmware update) warrant a different sort of
strategy to try to abbreviate, where collation falls short.  For this,
provide a columnar output that changes to line by line if stdout is not
a terminal.
2017-07-26 15:09:56 -04:00
Jarrod Johnson b5f016ad50 Provide support for removing update
This allows for cancelling and cleanup after reporting.
2017-07-26 14:10:04 -04:00
Jarrod Johnson eb3f5a8bbc Provide update status through API
Give visibility into the process.
2017-07-26 11:39:27 -04:00
Amanda Duffy 1d0b78267d Add nodebmcreset command and man page 2017-07-25 17:10:52 -04:00
Jarrod Johnson a40f015076 Phase 1 of firmware update support
Provide ability to launch firmware updates.
Next will be ability to enumerate, monitor, and
delete.
2017-07-25 17:01:32 -04:00
Amanda Duffy 4574d1bcc7 Merge remote-tracking branch 'upstream/master' 2017-07-25 15:40:06 -04:00
Jarrod Johnson 0bf21238aa Add bay number to IMM and XCC
The bay number can be opportunisticly grabbed, provide
that info in the discovery api.  In future, should add 'by-bay'
once we have enclosure data as well.
2017-07-25 12:07:18 -04:00
Jarrod Johnson 577456d999 Merge branch 'master' of github.com:jjohnson42/confluent 2017-07-20 11:05:19 -04:00
Jarrod Johnson 1dd40d36a1 Breakup logentries exceeding 65k
The data length of a log entry must not exceed 65k.  If an attempt is
made to log that much, break it up and duplicate the records.  It may make
sense to indicate a continuation explicitly, but for now just extend.
2017-07-20 11:05:06 -04:00
Jarrod Johnson ba9ea1acd8 Treat empty string same as undefined
If an administrator clears the cert fingerprint, they will
likely set it to ''.  In such a case, go down the 'no fingerprint'
path rather than reject it.
2017-07-20 10:20:22 -04:00
Jarrod Johnson 60756d9b41 Fix handling of numeric enclosure.bay
enclosure.bay is integer rather than string now.  Fix the filter
to use format, which is more robust in numeric versus string anyway.
Also, consistently make the underlying data integer rather than
sometimes string.
2017-07-20 10:12:53 -04:00
Jarrod Johnson 2795dfe7b9 Only mod noderange if bad nodes detected
This was triggering a defect in noderange. The
defect should be fixed, but in the meantime,
avoid tripping over it and looking weird anyway.
2017-07-18 15:37:37 -04:00
Jarrod Johnson a922de2ed6 Have nodeboot continue on non-failed nodes
If even one of a noderange failed to complete the
set boot device step, none would progress.  Change
the behavior so that exit code still happens and
processing does stop on timed out nodes, but go
ahead and reboot those that were fine.
2017-07-18 14:17:46 -04:00
Jarrod Johnson 5a2e4a669b Add a library for confluent version of 'xcoll'
Add a diff function with colorized intra-line diff info
2017-06-29 16:58:02 -04:00
Jarrod Johnson c2115f4df9 Fix get/set global with the stateless mode change
Since supporting stateless made the init() optional, the *_global functions
would not work if called first.  Correct this oversight.
2017-06-29 13:08:23 -04:00
Jarrod Johnson fa6650a072 Non-linux fallback for list_interface_indexes()
When errors suggest we are not in linux, make a best
effort using netifaces.
2017-06-29 10:33:10 -04:00
Jarrod Johnson 1116fed1e7 Minor style fix 2017-06-29 10:24:13 -04:00
Jarrod Johnson 0745ab0fdf Auto-encode unicode if needed
If unicode comes in to be crypted and fails, be explicit about utf-8 encoding.
2017-06-29 10:20:24 -04:00
Jarrod Johnson aeb3bd2444 Add a stateless configmanager mode
Certain embodiments of confluent may not
want to persist configuration.  Enable
an opt-in full-volatile config mode.
2017-06-29 10:17:17 -04:00
Jarrod Johnson 5dc2d8c8be Prefer SLP data on probe if available
Avoid attempting login on probe if at all possible.
2017-06-28 16:21:57 -04:00
Jarrod Johnson dc23793d32 Reorder SLP services
Make the most important one likely to be first, so that the
attributes filled out later to fixate on the most relevant.
2017-06-28 16:20:58 -04:00
Jarrod Johnson 3bcf236744 Fix serial numbers with leading spaces
Sometimes the string may have leading spaces, remove those for sane presentation.
2017-06-28 10:13:50 -04:00
Jarrod Johnson ea9caa470b Fix unexpected error on retrieving nodegroup attributes
Detect and more specifically report error message when an unknown group
is used for nodegroup commands.
2017-06-27 15:06:59 -04:00
Jarrod Johnson a894624403 Fix python 2.6 compatibility in log
python 2.6 requires a numeric argument to {}
2017-06-27 14:48:33 -04:00
Jarrod Johnson a3c06a00bf Fix confetty behavior when TERM not set
Particularly in non-interactive ssh, TERM is not set.
Assume empty string if TERM is not set.
2017-06-27 14:04:26 -04:00
Jarrod Johnson 86ed339b48 Add localonly mode to SLP
Sometimes in a likely mismatched IP situation, some SLP things will manage to reply and slow
down.  For now in the case of mismatched IPv4 being likely, provide a mode fixated on link local.
2017-06-26 09:30:23 -04:00
Jarrod Johnson ff6e4d7ab6 Fix up slp.py for windows compatibility
python in Windows does not have a required constant
in socket, hard bake the value if not defined in the module.
2017-06-26 09:23:41 -04:00
Jarrod Johnson 8126ec3791 Implement 'memory' console.logging scheme
Provide way for VT to be maintained without log to file.
2017-06-26 09:18:30 -04:00
Jarrod Johnson 8fab1ce9eb Fix permissions on buildindex.sh 2017-06-26 08:46:22 -04:00
Jarrod Johnson 9078fb01c4 Fix missing data from 1.5.0 merge 2017-06-23 08:45:34 -04:00
Jarrod Johnson e4186841b4 Correct the stub functions to work 2017-06-22 15:50:24 -04:00
Jarrod Johnson 1526a9b92d Add functions to stub out globbing
noderanges use [], and bash can do undesirable things.
Since these commands by and large do not reference files,
or at least files likely to be globbed, disable globbing.
2017-06-22 15:42:30 -04:00
Jarrod Johnson bc1b1a9676 Update nodeshell documentation on stdout/stderr 2017-06-21 14:30:54 -04:00
Jarrod Johnson f4267e6013 Add missing files from the ThinkSystem merge 2017-06-21 14:02:59 -04:00
Jarrod Johnson e0cc67f57a Implement Lenovo Thinksystem and discovery support 2017-06-20 14:56:24 -04:00
Jarrod Johnson 6117a90372 Provide a script to summarize hangtraces files 2017-05-22 09:25:51 -04:00
Amanda Duffy 3a53b2c014 Merge remote-tracking branch 'refs/remotes/xcat2/master' 2017-05-02 15:44:56 -04:00
170 changed files with 20089 additions and 8101 deletions
+114
View File
@@ -0,0 +1,114 @@
#!/usr/bin/python2
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2017 Lenovo
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# This is a utility to bring xcoll (plus enhancements) to confluent
# the core engine is textgroup.py, this simply provides a CLI to use
# generically
import optparse
import os
import select
import sys
path = os.path.dirname(os.path.realpath(__file__))
path = os.path.realpath(os.path.join(path, '..', 'lib', 'python'))
if path.startswith('/opt'):
sys.path.append(path)
import confluent.textgroup as tg
import confluent.client
argparser = optparse.OptionParser(usage="Usage: <other command> | %prog [options]")
argparser.add_option('-a', '--abbreviate', action='store_true',
help='Attempt to use confluent server to shorten noderanges')
argparser.add_option('-b', '--base',
help='Use given node as reference for comparison when '
'using -d, instead of using the most common result')
argparser.add_option('-d', '--diff', action='store_true',
help='Show what differs between most common '
'output group and others')
argparser.add_option('-w', '--watch', action='store_true',
help='Show intermediate results while running')
argparser.add_option('-s', '--skipcommon', action='store_true',
help='Do not print most common result, only non modal '
'groups, useful when combined with -d')
argparser.add_option('-c', '--count', action='store_true',
help='Also display count of nodes in a given group')
argparser.add_option('-r', '--reverse', action='store_true',
help='Reverse sort order to show biggest output group '
'last')
argparser.add_option('-l', '--log', action='store', type='string', dest='log',
help='Log each output to file, using {node} as a placeholder for node.')
(options, args) = argparser.parse_args()
if sys.stdin.isatty():
argparser.print_help()
sys.exit(1)
grouped = tg.GroupedData()
if options.abbreviate:
grouped = tg.GroupedData(confluent.client.Command())
else:
grouped = tg.GroupedData()
def print_current():
if options.diff:
grouped.print_deviants(skipmodal=options.skipcommon, count=options.count,
reverse=options.reverse, basenode=options.base)
else:
grouped.print_all(skipmodal=options.skipcommon,
count=options.count,
reverse=options.reverse)
sys.stdout.flush()
fullline = sys.stdin.readline()
printpending = True
clearpending = False
holdoff = 0
while fullline:
for line in fullline.split('\n'):
if not line:
continue
if ': ' not in line:
line = 'UNKNOWN: ' + line
if options.log:
node, output = line.split(': ', 1)
currlog = options.log.format(node=node, nodename=node)
with open(currlog, mode='a') as log:
log.write(output + '\n')
continue
grouped.add_line(*line.split(': ', 1))
if options.watch:
if not holdoff:
holdoff = os.times()[4] + 0.250
if (holdoff < os.times()[4] or
not select.select((sys.stdin,), (), (), 0.250)[0]):
# print now, nothing pending
holdoff = 0
sys.stdout.write('\x1b[2J\x1b[;H') # clear screen
print_current()
printpending = False
clearpending = True
else:
printpending = True
fullline = sys.stdin.readline()
if printpending:
if clearpending:
sys.stdout.write('\x1b[2J\x1b[;H') # clear screen
print_current()
+296 -132
View File
@@ -1,8 +1,8 @@
#!/usr/bin/env python
#!/usr/bin/python2
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2014 IBM Corporation
# Copyright 2015-2016 Lenovo
# Copyright 2015-2018 Lenovo
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -47,7 +47,9 @@ import optparse
import os
import select
import shlex
import signal
import socket
import struct
import sys
import time
try:
@@ -56,7 +58,10 @@ try:
import tty
except ImportError:
pass
try:
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
except AttributeError:
pass
exitcode = 0
consoleonly = False
consolename = ""
@@ -72,6 +77,7 @@ import confluent.tlvdata as tlvdata
import confluent.client as client
conserversequence = '\x05c' # ctrl-e, c
clearpowermessage = False
oldtcattr = None
fd = sys.stdin
@@ -83,8 +89,44 @@ except NameError:
netserver = None
laststate = {}
try:
input = raw_input
except NameError:
pass
class BailOut(Exception):
def __init__(self, errorcode=0):
self.errorcode = errorcode
def print_help():
print("confetty provides a filesystem like interface to confluent. "
"Navigation is done using the same commands as would be used in a "
"filesystem. Tab completion is supported to aid in navigation,"
"as is up arrow to recall previous commands and control-r to search"
"previous command history, similar to using bash\n\n"
"The supported commands are:\n"
"cd [location] - Set the current command context, similar to a "
"working directory.\n"
"show [resource] - Present the information about the specified "
"resource, or current context if omitted.\n"
"create [resource] attributename=value attributename=value - Create "
"a new instance of a resource.\n"
"remove [resource] - Remove a resource from a list\n"
"set [resource] attributename=value attributename=value - Change "
"the specified attributes value for the given resource name\n"
"unset [resource] attributename - Clear any value for the given "
"attribute names on a resource.\n"
"start [resource] - When used on a text session resource, it "
"enters remote terminal mode. In this mode, use 'ctrl-e, c, ?' for "
"help"
)
#TODO(jjohnson2): lookup context help for 'target' variable, perhaps
#common with the api document
def updatestatus(stateinfo={}):
global powerstate, powertime, clearpowermessage
status = consolename
info = []
for statekey in stateinfo:
@@ -99,6 +141,15 @@ def updatestatus(stateinfo={}):
# error will be repeated if relevant
# avoid keeping it around as stale
del laststate['error']
if 'state' in stateinfo: # currently only read power means anything
newpowerstate = stateinfo['state']['value']
if newpowerstate != powerstate and newpowerstate == 'off':
sys.stdout.write("\x1b[2J\x1b[;H[powered off]\r\n")
clearpowermessage = True
if newpowerstate == 'on' and clearpowermessage:
sys.stdout.write("\x1b[2J\x1b[;H")
clearpowermessage = False
powerstate = newpowerstate
if 'clientcount' in laststate and laststate['clientcount'] != 1:
info.append('clients: %d' % laststate['clientcount'])
if 'bufferage' in stateinfo and stateinfo['bufferage'] is not None:
@@ -106,14 +157,14 @@ def updatestatus(stateinfo={}):
if 'showtime' in laststate:
showtime = laststate['showtime']
age = time.time() - laststate['showtime']
if age > 86400: # older than one day
if age > 86400: # older than one day
# disambiguate by putting date in and time
info.append(time.strftime('%m-%dT%H:%M', time.localtime(showtime)))
else:
info.append(time.strftime('%H:%M', time.localtime(showtime)))
if info:
status += ' [' + ','.join(info) + ']'
if os.environ['TERM'] not in ('linux'):
if os.environ.get('TERM', '') not in ('linux'):
sys.stdout.write('\x1b]0;console: %s\x07' % status)
sys.stdout.flush()
@@ -145,12 +196,12 @@ def recurse_format(datum, levels=0):
def prompt():
if os.environ['TERM'] not in ('linux'):
if os.environ.get('TERM', '') not in ('linux'):
sys.stdout.write('\x1b]0;confetty: %s\x07' % target)
try:
return raw_input(target + ' -> ')
return input(target + ' -> ')
except KeyboardInterrupt:
print ""
print("")
return ""
except EOFError: # ctrl-d
print("exit")
@@ -169,6 +220,7 @@ valid_commands = [
'remove',
'rm',
'delete',
'help',
]
candidates = None
@@ -238,7 +290,7 @@ def parse_command(command):
try:
args = shlex.split(command, posix=True)
except ValueError as ve:
print('Error: ' + ve.message)
print('Error: ' + str(ve))
return []
return args
@@ -248,19 +300,22 @@ currchildren = None
def print_result(res):
if 'errorcode' in res or 'error' in res:
print res['error']
print(res['error'])
return
if 'databynode' in res:
print_result(res['databynode'])
return
for key in res.iterkeys():
for key in sorted(res):
notes = []
if res[key] is None:
attrstr = '%s=""' % key
elif type(res[key]) == list:
attrstr = '%s=%s' % (key, recurse_format(res[key]))
elif not isinstance(res[key], dict):
print '{0}: {1}'.format(key, res[key])
try:
print('{0}: {1}'.format(key, res[key]))
except UnicodeEncodeError:
print('{0}: {1}'.format(key, repr(res[key])))
continue
elif 'value' in res[key] and res[key]['value'] is not None:
attrstr = '%s="%s"' % (key, res[key]['value'])
@@ -273,7 +328,7 @@ def print_result(res):
else:
sys.stdout.write('{0}: '.format(key))
if isinstance(res[key], str) or isinstance(res[key], unicode):
print res[key]
print(res[key])
else:
print_result(res[key])
continue
@@ -306,7 +361,11 @@ def do_command(command, server):
return
argv[0] = argv[0].lower()
if argv[0] == 'exit':
sys.exit(0)
if os.environ.get('TERM', '') not in ('linux'):
sys.stdout.write('\x1b]0;\x07')
raise Bailout()
elif argv[0] in ('help', '?'):
return print_help()
elif argv[0] == 'cd':
otarget = target
if len(argv) > 1:
@@ -348,15 +407,30 @@ def do_command(command, server):
elif argv[0] in ('cat', 'show', 'ls', 'dir'):
if len(argv) > 1:
targpath = fullpath_target(argv[1])
if argv[0] in ('ls', 'dir'):
if targpath[-1] != '/':
# could still be a directory, fetch the parent..
childname = targpath[targpath.rindex('/') + 1:]
parentpath = targpath[:targpath.rindex('/') + 1]
if parentpath != '/noderange/':
# if it were /noderange/, then it's a directory
# even though parent won't tell us that
for res in session.read(parentpath, server):
try:
if res['item']['href'] == childname:
print(childname)
return
except KeyError:
pass
else:
targpath = target
for res in session.read(targpath):
if 'item' in res: # a link relation
if type(res['item']) == dict:
print res['item']["href"]
print(res['item']["href"])
else:
for item in res['item']:
print item["href"]
print(item["href"])
else: # generic attributes to list
if 'error' in res:
sys.stderr.write(res['error'] + '\n')
@@ -370,6 +444,10 @@ def do_command(command, server):
currconsole = targpath
startrequest = {'operation': 'start', 'path': targpath,
'parameters': {}}
height, width = struct.unpack(
'hh', fcntl.ioctl(sys.stdout, termios.TIOCGWINSZ, b'....'))[:2]
startrequest['parameters']['width'] = width
startrequest['parameters']['height'] = height
for param in argv[2:]:
(parmkey, parmval) = param.split("=")
startrequest['parameters'][parmkey] = parmval
@@ -410,18 +488,33 @@ def createresource(args):
if keydata is None:
return
targpath = fullpath_target(resname)
collection, _, resname = targpath.rpartition('/')
keydata['name'] = resname
if targpath.startswith('/noderange//'):
collection = targpath
else:
collection, _, resname = targpath.rpartition('/')
if 'name' not in keydata:
keydata['name'] = resname
makecall(session.create, (collection, keydata))
def makecall(callout, args):
global exitcode
for response in callout(*args):
if 'deleted' in response:
print("Deleted: " + response['deleted'])
if 'created' in response:
print("Created: " + response['created'])
if 'error' in response:
if 'errorcode' in response:
exitcode = response['errorcode']
sys.stderr.write('Error: ' + response['error'] + '\n')
if 'databynode' in response:
lresponse = response['databynode']
for node in lresponse:
if 'errorcode' in lresponse[node]:
exitcode = lresponse[node]['errorcode']
if 'error' in lresponse[node]:
sys.stderr.write('{0}: Error - {1}\n'.format(node, lresponse[node]['error']))
def clearvalues(resource, attribs):
@@ -504,11 +597,20 @@ def fullpath_target(currpath, forcepath=False):
ntarget += '/'
return ntarget
def do_resize(a, b):
if not inconsole:
return
height, width = struct.unpack(
'hh', fcntl.ioctl(sys.stdout, termios.TIOCGWINSZ, b'....'))[:2]
tlvdata.send(session.connection, {'operation': 'resize', 'width': width,
'height': height})
def startconsole(nodename):
global inconsole
global consolename
global didconsole
signal.signal(signal.SIGWINCH, do_resize)
didconsole = True
consolename = nodename
tty.setraw(sys.stdin.fileno())
@@ -526,8 +628,13 @@ def quitconfetty(code=0, fullexit=False, fixterm=True):
fcntl.fcntl(sys.stdin.fileno(), fcntl.F_SETFL, currfl ^ os.O_NONBLOCK)
if oldtcattr is not None:
termios.tcsetattr(sys.stdin.fileno(), termios.TCSANOW, oldtcattr)
# Request default color scheme, to undo potential weirdness of terminal
if sys.stdout.isatty():
sys.stdout.write('\x1b[m')
if fullexit:
sys.exit(code)
if sys.stdout.isatty() and os.environ.get('TERM', '') not in ('linux'):
sys.stdout.write('\x1b]0;\x07')
raise BailOut(code)
else:
tlvdata.send(session.connection, {'operation': 'stop',
'path': currconsole})
@@ -652,10 +759,25 @@ def conserver_command(filehandle, localcommand):
print("Unknown power state.]\r")
check_power_state()
elif localcommand[0] == 'r':
sys.stdout.write('\x1b7\x1b[999;999H\x1b[6n')
sys.stdout.flush()
reply = ''
while 'R' not in reply:
try:
reply += sys.stdin.read(1)
except IOError:
pass
reply = reply.replace('\x1b[', '')
reply = reply.replace('R', '')
height, width = reply.split(';')
sys.stdout.write('\x1b8')
sys.stdout.flush()
print('sending stty commands]')
return 'stty columns {0}\rstty rows {1}\r'.format(width, height)
elif localcommand[0] == '?':
print("help]\r")
print(". disconnect\r")
print(". exit console\r")
print("b break\r")
print("o reopen\r")
print("po power off\r")
@@ -663,6 +785,7 @@ def conserver_command(filehandle, localcommand):
print("pbs boot to setup\r")
print("pbn boot to network\r")
print("pb<ent> boot to default\r")
print("r send stty command to resize terminal\r")
print("<cr> abort command\r")
elif localcommand[0] == '\x0d':
print("ignored]\r")
@@ -672,7 +795,10 @@ def conserver_command(filehandle, localcommand):
def get_command_bytes(filehandle, localcommand, cmdlen):
while len(localcommand) < cmdlen:
ready, _, _ = select.select((filehandle,), (), (), 1)
try:
ready, _, _ = select.select((filehandle,), (), (), 1)
except select.error:
ready = ()
if ready:
localcommand += filehandle.read()
return localcommand
@@ -685,7 +811,10 @@ def check_escape_seq(currinput, filehandle):
sys.stdout.flush()
return conserver_command(
filehandle, currinput[len(conserversequence):])
ready, _, _ = select.select((filehandle,), (), (), 3)
try:
ready, _, _ = select.select((filehandle,), (), (), 3)
except select.error:
ready = ()
if not ready: # 3 seconds of no typing
break
currinput += filehandle.read()
@@ -698,6 +827,10 @@ parser.add_option("-s", "--server", dest="netserver",
parser.add_option("-c", "--control", dest="controlpath",
help="Path to offer terminal control",
metavar="PATH")
parser.add_option(
'-m', '--mintime', default=0,
help='Minimum time to run or else pause for input (used to keep a '
'terminal from closing quickly on error)')
opts, shellargs = parser.parse_args()
username = None
@@ -722,129 +855,160 @@ def server_connect():
passphrase = os.environ['CONFLUENT_PASSPHRASE']
session.authenticate(username, passphrase)
while not session.authenticated:
username = raw_input("Name: ")
username = input("Name: ")
passphrase = getpass.getpass("Passphrase: ")
session.authenticate(username, passphrase)
def check_power_state():
tlvdata.send(
session.connection,
{'operation': 'retrieve',
'path': '/nodes/' + consolename + '/power/state'})
return
try:
server_connect()
except EOFError, KeyboardInterrupt:
sys.exit(0)
except socket.gaierror:
sys.stderr.write('Could not connect to confluent\n')
sys.exit(1)
# clear on start can help with readable of TUI, but it
# can be annoying, so for now don't do it.
# sys.stdout.write('\x1b[H\x1b[J')
# sys.stdout.flush()
if sys.stdout.isatty():
import readline
readline.parse_and_bind("tab: complete")
readline.parse_and_bind("set bell-style none")
readline.set_completer(completer)
doexit = False
inconsole = False
pendingcommand = ""
session_node = get_session_node(shellargs)
if session_node is not None:
consoleonly = True
do_command("start /nodes/%s/console/session" % session_node, netserver)
doexit = True
elif shellargs:
command = " ".join(shellargs)
do_command(command, netserver)
quitconfetty(fullexit=True, fixterm=False)
powerstate = None
powertime = None
def main():
global inconsole
try:
server_connect()
except (EOFError, KeyboardInterrupt) as _:
raise BailOut(0)
except socket.gaierror:
sys.stderr.write('Could not connect to confluent\n')
raise BailOut(1)
# clear on start can help with readable of TUI, but it
# can be annoying, so for now don't do it.
# sys.stdout.write('\x1b[H\x1b[J')
# sys.stdout.flush()
global powerstate, powertime, clearpowermessage
def check_power_state():
global powerstate, powertime
for rsp in session.read('/nodes/' + consolename + '/power/state'):
if type(rsp) == dict and 'state' in rsp:
powerstate = rsp['state']['value']
powertime = time.time()
if powerstate == 'off':
sys.stdout.write("\r\n[powered off]\r\n")
elif type(rsp) == dict and '_requestdone' in rsp:
break
elif type(rsp) == dict:
updatestatus(rsp)
else:
sys.stdout.write(rsp)
sys.stdout.flush()
if sys.stdout.isatty():
readline.parse_and_bind("tab: complete")
readline.parse_and_bind("set bell-style none")
dl = readline.get_completer_delims().replace('-', '')
readline.set_completer_delims(dl)
readline.set_completer(completer)
while inconsole or not doexit:
if inconsole:
rdylist, _, _ = select.select(
(sys.stdin, session.connection), (), (), 60)
for fh in rdylist:
if fh == session.connection:
# this only should get called in the
# case of a console session
# each command should slurp up all relevant
# recv potential
#fh.read()
try:
data = tlvdata.recv(fh)
except Exception:
data = None
if type(data) == dict:
updatestatus(data)
continue
if data is not None:
sys.stdout.write(data)
now = time.time()
if ('showtime' not in laststate or
(now // 60) != laststate['showtime'] // 60):
# don't bother churning if minute does not change
laststate['showtime'] = now
updatestatus()
sys.stdout.flush()
else:
deadline = 5
connected = False
while not connected and deadline > 0:
try:
server_connect()
connected = True
except (socket.gaierror, socket.error):
pass
if not connected:
time.sleep(1)
deadline -=1
if connected:
do_command(
"start /nodes/%s/console/session skipreplay=True" % consolename,
netserver)
else:
doexit = True
inconsole = False
sys.stdout.write("\r\n[remote disconnected]\r\n")
break
else:
myinput = fh.read()
myinput = check_escape_seq(myinput, fh)
if myinput:
tlvdata.send(session.connection, myinput)
if powerstate is None or powertime < time.time() - 60: # Check powerstate every 60 seconds
check_power_state()
doexit = False
inconsole = False
pendingcommand = ""
session_node = get_session_node(shellargs)
if session_node is not None:
consoleonly = True
do_command("start /nodes/%s/console/session" % session_node, netserver)
doexit = True
elif shellargs:
command = " ".join(shellargs)
do_command(command, netserver)
quitconfetty(fullexit=True, fixterm=False)
else:
currcommand = prompt()
try:
do_command(currcommand, netserver)
except socket.error:
powerstate = None
powertime = None
while inconsole or not doexit:
if inconsole:
try:
rdylist, _, _ = select.select(
(sys.stdin, session.connection), (), (), 10)
except select.error:
rdylist = ()
for fh in rdylist:
if fh == session.connection:
# this only should get called in the
# case of a console session
# each command should slurp up all relevant
# recv potential
#fh.read()
try:
data = tlvdata.recv(fh)
except Exception:
data = None
if type(data) == dict:
updatestatus(data)
continue
if data is not None:
data = client.stringify(data)
if clearpowermessage:
sys.stdout.write("\x1b[2J\x1b[;H")
clearpowermessage = False
try:
sys.stdout.write(data)
except IOError: # Some times circumstances are bad
# resort to byte at a time...
for d in data:
sys.stdout.write(d)
now = time.time()
if ('showtime' not in laststate or
(now // 60) != laststate['showtime'] // 60):
# don't bother churning if minute does not change
laststate['showtime'] = now
updatestatus()
sys.stdout.flush()
else:
deadline = 5
connected = False
while not connected and deadline > 0:
try:
server_connect()
connected = True
except (socket.gaierror, socket.error):
pass
if not connected:
time.sleep(1)
deadline -=1
if connected:
do_command(
"start /nodes/%s/console/session skipreplay=True" % consolename,
netserver)
else:
doexit = True
inconsole = False
sys.stdout.write("\r\n[remote disconnected]\r\n")
break
else:
try:
myinput = fh.read()
myinput = check_escape_seq(myinput, fh)
if myinput:
tlvdata.send(session.connection, myinput)
except IOError:
pass
if powerstate is None or powertime < time.time() - 10: # Check powerstate every 10 seconds
powertime = time.time()
powerstate = True
check_power_state()
else:
currcommand = prompt()
try:
server_connect()
do_command(currcommand, netserver)
except socket.error:
doexit = True
sys.stdout.write('Lost connection to server')
quitconfetty(fullexit=True)
try:
server_connect()
do_command(currcommand, netserver)
except socket.error:
doexit = True
sys.stdout.write('Lost connection to server')
quitconfetty(fullexit=True)
if __name__ == '__main__':
errcode = 0
deadline = 0
if opts.mintime:
deadline = os.times()[4] + float(opts.mintime)
try:
main()
except BailOut as e:
errcode = e.errorcode
finally:
if deadline and os.times()[4] < deadline:
sys.stderr.write('[Exited early, hit enter to continue]')
sys.stdin.readline()
if errcode == 0:
errcode = exitcode
sys.exit(errcode)
+71
View File
@@ -0,0 +1,71 @@
#!/usr/bin/python2
import optparse
import signal
import sys
import os
try:
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
except AttributeError:
pass
path = os.path.dirname(os.path.realpath(__file__))
path = os.path.realpath(os.path.join(path, '..', 'lib', 'python'))
if path.startswith('/opt'):
sys.path.append(path)
import confluent.client as client
import confluent.sortutil as sortutil
def lookupdata(data, key):
ret = data.get(key, {}).get('value', '')
if ret is None:
ret = ''
return ret
def main():
argparser = optparse.OptionParser(
usage='''\n %prog noderange -o ansible.hosts
\n ''')
argparser.add_option('-o', '--output',
help='Ansible hosts file')
(options, args) = argparser.parse_args()
try:
noderange = args[0]
except IndexError:
argparser.print_help()
sys.exit(1)
if not options.output:
sys.stderr.write('Output file must be specified by -o\n')
sys.exit(1)
sess = client.Command()
databynode = {}
for res in sess.read('/noderange/{0}/attributes/all'.format(noderange)):
for node in res.get('databynode', {}):
if node not in databynode:
databynode[node] = {}
databynode[node].update(res['databynode'][node])
nodesbygroup = {}
with open(options.output, 'w') as importfile:
needempty = False
for node in sortutil.natural_sort(databynode):
data = databynode[node]
if not data.get('groups', []):
importfile.write(node + '\n')
needempty = True
for g in data.get('groups', []):
if g not in nodesbygroup:
nodesbygroup[g] = set([node])
else:
nodesbygroup[g].add(node)
if needempty:
importfile.write('\n')
for group in sortutil.natural_sort(nodesbygroup):
importfile.write('[{0}]\n'.format(group))
for node in sortutil.natural_sort(nodesbygroup[group]):
importfile.write('{0}\n'.format(node))
importfile.write('\n')
if __name__ == '__main__':
main()
+76
View File
@@ -0,0 +1,76 @@
#!/usr/bin/python2
import csv
import optparse
import signal
import sys
import os
try:
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
except AttributeError:
pass
path = os.path.dirname(os.path.realpath(__file__))
path = os.path.realpath(os.path.join(path, '..', 'lib', 'python'))
if path.startswith('/opt'):
sys.path.append(path)
import confluent.client as client
import confluent.sortutil as sortutil
headers = '# Type,Serial Number,Current IP,Current username,Current password,New password,Recovery password,Switch enable password,New IPv4,IPv4 Subnet mask,IPv4 Default gateway,IPv4 DNS1,IPv4 DNS2,New IPv6,IPv6 Prefix,IPv6 Default gateway,IPv6 DNS1,IPv6 DNS2,Domain,Host name,Display name,Rack,Lowest Rack Unit,Height,Force,Stored credentials ID,Managed authentication,Group Name'.split(',')
def lookupdata(data, key):
ret = data.get(key, {}).get('value', '')
if ret is None:
ret = ''
return ret
def main():
argparser = optparse.OptionParser(
usage='''\n %prog noderange -o bulkimport.csv
\n ''')
argparser.add_option('-o', '--output',
help='File to write for bulk import into xClarity Administrator')
(options, args) = argparser.parse_args()
try:
noderange = args[0]
except IndexError:
argparser.print_help()
sys.exit(1)
if not options.output:
sys.stderr.write('Output file must be specified by -o\n')
sys.exit(1)
if 'XCCUSER' not in os.environ or 'XCCPASS' not in os.environ:
sys.stderr.write('Must specify XCCUSER and XCCPASS in environment variables\n')
sys.exit(1)
xccuser = os.environ['XCCUSER']
xccpass = os.environ['XCCPASS']
sess = client.Command()
databynode = {}
for res in sess.read('/noderange/{0}/attributes/all'.format(noderange)):
for node in res.get('databynode', {}):
if node not in databynode:
databynode[node] = {}
databynode[node].update(res['databynode'][node])
for res in sess.read(
'/noderange/{0}/configuration/management_controller/net_interfaces/management'.format(
noderange)):
for node in res.get('databynode', {}):
currip = res['databynode'][node].get('ipv4_address', {}).get(
'value', '')
if currip:
databynode[node]['hardwaremanagement.manager'] = {
'value': currip.split('/', 1)[0]}
with open(options.output, 'w') as importfile:
bulkimport = csv.writer(importfile)
bulkimport.writerow(headers)
for node in sortutil.natural_sort(databynode):
data = databynode[node]
row = ['server', lookupdata(data, 'id.serial'), lookupdata(data, 'hardwaremanagement.manager'), xccuser, xccpass, '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', node, lookupdata(data, 'location.rack'), lookupdata(data, 'location.u'), '', '', '','', '']
bulkimport.writerow(row)
if __name__ == '__main__':
main()
+103
View File
@@ -0,0 +1,103 @@
#!/usr/bin/python2
import csv
import optparse
import signal
import sys
import os
try:
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
except AttributeError:
pass
path = os.path.dirname(os.path.realpath(__file__))
path = os.path.realpath(os.path.join(path, '..', 'lib', 'python'))
if path.startswith('/opt'):
sys.path.append(path)
import confluent.client as client
import confluent.sortutil as sortutil
def lookupdata(data, key):
ret = data.get(key, {}).get('value', '')
if ret is None:
ret = ''
return ret
def main():
argparser = optparse.OptionParser(
usage='''\n %prog noderange -o xcatnodes.def
\n ''')
argparser.add_option('-o', '--output',
help='xCAT stanza file')
argparser.add_option('-m', '--macs',
help='xCAT macs.csv to write')
(options, args) = argparser.parse_args()
try:
noderange = args[0]
except IndexError:
argparser.print_help()
sys.exit(1)
if not (options.output or options.macs):
sys.stderr.write('Output file must be specified by -o or -m\n')
sys.exit(1)
sess = client.Command()
databynode = {}
for res in sess.read('/noderange/{0}/attributes/all'.format(noderange)):
for node in res.get('databynode', {}):
if node not in databynode:
databynode[node] = {}
databynode[node].update(res['databynode'][node])
if options.output:
with open(options.output, 'w') as importfile:
for node in sortutil.natural_sort(databynode):
xcatattrs = collect_attribute_data(databynode, node)
importfile.write('{0}:\n'.format(node))
importfile.write(' objtype=node\n')
importfile.write(' arch=x86_64\n')
importfile.write(' netboot=xnba\n')
importfile.write(' mgt=ipmi\n')
for attr in xcatattrs:
if xcatattrs[attr] is None:
continue
importfile.write(' {0}={1}\n'.format(attr,
xcatattrs[attr]))
importfile.write('\n')
if options.macs:
with open(options.macs, 'w') as importfile:
macsv = csv.writer(importfile)
macsv.writerow(['#node', 'mac'])
for node in sortutil.natural_sort(databynode):
xcatattrs = collect_attribute_data(databynode, node)
macsv.writerow([node, xcatattrs['mac']])
def collect_attribute_data(databynode, node):
data = databynode[node]
xcatattrs = {}
xcatattrs['groups'] = ','.join(data.get('groups', []))
xcatattrs['bmc'] = data.get('hardwaremanagement.manager', {}).get(
'value', None)
xcatattrs['mpa'] = data.get('enclosure.manager', {}).get(
'value', None)
xcatattrs['slotid'] = data.get('enclosure.bay', {}).get(
'value', None)
gotmac = False
for key in data:
if key.startswith('net.') and 'hwaddr' in key:
currmac = data[key].get('value', None)
if currmac:
if gotmac:
sys.stderr.write(
'Ignoring {0} and using only {1} for mac, '
'multiple macs not supported by '
'confluent2xcat\n'.format(key, gotmac))
continue
gotmac = key
xcatattrs['mac'] = currmac
return xcatattrs
if __name__ == '__main__':
main()
+19
View File
@@ -0,0 +1,19 @@
#!/bin/sh
# This will take a given directory and make a 'big floppy image'
# out of it, suitable for nodemedia upload.
if [ -z "$1" -o -z "$2" ]; then
echo "Usage: $0 <directory> <imagefile>"
exit 1
fi
# Get the needed payload side
SIZE=$(du -sB 512 $1|awk '{print $1}')
ENTRIES=$(find $1 |wc -l)
# Also, each file and directory has overhead, pad size by 32kb per file,
# which should be overkill but other values proved to be inadequate
# A deeper understanding of VFAT would probably allow for more precise value
SIZE=$((SIZE + ENTRIES * 64))
dd if=/dev/zero of=$2 bs=512 count=$SIZE
# Make a big single sided floppy with many many tracks, saves on complex math
mformat -i $2 -d 1 -t $SIZE -s 1 -h 1 ::
mcopy -i $2 -s $1/* ::
+46 -9
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/python2
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2017 Lenovo
@@ -17,10 +17,17 @@
__author__ = 'alin37'
from getpass import getpass
import optparse
import os
import signal
import sys
try:
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
except AttributeError:
pass
path = os.path.dirname(os.path.realpath(__file__))
path = os.path.realpath(os.path.join(path, '..', 'lib', 'python'))
if path.startswith('/opt'):
@@ -29,13 +36,23 @@ if path.startswith('/opt'):
import confluent.client as client
argparser = optparse.OptionParser(
usage='''\n %prog [options] noderange [list of attributes] \
\n %prog [options] noderange attribute1=value1,attribute2=value,...
usage='''\n %prog [-b] noderange [list of attributes or 'all'] \
\n %prog -c noderange <list of attributes> \
\n %prog -e noderange <attribute names to set> \
\n %prog noderange attribute1=value1 attribute2=value,...
\n ''')
argparser.add_option('-b', '--blame', action='store_true',
help='Show information about how attributes inherited')
argparser.add_option('-e', '--environment', action='store_true',
help='Set attributes, but from environment variable of '
'same name')
argparser.add_option('-c', '--clear', action='store_true',
help='Clear variables')
help='Clear attributes')
argparser.add_option('-p', '--prompt', action='store_true',
help='Prompt for attribute values interactively')
argparser.add_option('-m', '--maxnodes', type='int',
help='Prompt if trying to set attributes on more '
'than specified number of nodes')
(options, args) = argparser.parse_args()
@@ -46,7 +63,9 @@ try:
noderange = args[0]
nodelist = '/noderange/{0}/nodes/'.format(noderange)
except IndexError:
nodelist = '/nodes/'
argparser.print_help()
sys.exit(1)
client.check_globbing(noderange)
session = client.Command()
exitcode = 0
@@ -54,8 +73,25 @@ exitcode = 0
nodetype="noderange"
if len(args) > 1:
if "=" in args[1]:
exitcode=client.updateattrib(session,args,nodetype, noderange, options)
if "=" in args[1] or options.clear or options.environment or options.prompt:
if "=" in args[1] and options.clear:
print("Can not clear and set at the same time!")
argparser.print_help()
sys.exit(1)
argassign = None
if options.prompt:
argassign = {}
for arg in args[1:]:
oneval = 1
twoval = 2
while oneval != twoval:
oneval = getpass('Enter value for {0}: '.format(arg))
twoval = getpass('Confirm value for {0}: '.format(arg))
if oneval != twoval:
print('Values did not match.')
argassign[arg] = twoval
session.stop_if_noderange_over(noderange, options.maxnodes)
exitcode=client.updateattrib(session,args,nodetype, noderange, options, argassign)
try:
# setting user output to what the user inputs
if args[1] == 'all':
@@ -65,6 +101,7 @@ if len(args) > 1:
showtype = 'current'
requestargs=args[2:]
else:
showtype = 'all'
requestargs=args[1:]
except:
pass
@@ -93,6 +130,6 @@ else:
sys.stderr.write(res['error'] + '\n')
exitcode = 1
else:
print res['item']['href'].replace('/', '')
print(res['item']['href'].replace('/', ''))
sys.exit(exitcode)
sys.exit(exitcode)
+64
View File
@@ -0,0 +1,64 @@
#!/usr/bin/python2
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2015-2017 Lenovo
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import optparse
import os
import signal
import sys
try:
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
except AttributeError:
pass
path = os.path.dirname(os.path.realpath(__file__))
path = os.path.realpath(os.path.join(path, '..', 'lib', 'python'))
if path.startswith('/opt'):
sys.path.append(path)
import confluent.client as client
argparser = optparse.OptionParser(usage="Usage: %prog <noderange>")
argparser.add_option('-m', '--maxnodes', type='int',
help='Number of nodes to affect before prompting for confirmation')
(options, args) = argparser.parse_args()
try:
noderange = args[0]
except IndexError:
argparser.print_help()
sys.exit(1)
client.check_globbing(noderange)
session = client.Command()
exitcode = 0
errorNodes = set([])
session.stop_if_noderange_over(noderange, options.maxnodes)
success = session.simple_noderange_command(noderange, 'configuration/management_controller/reset', 'reset', key='state', errnodes=errorNodes) # = 0 if successful
# Determine which nodes were successful and print them
allNodes = set([])
for node in session.read('/noderange/{0}/nodes/'.format(noderange)):
allNodes.add(node['item']['href'].replace("/", ""))
goodNodes = allNodes - errorNodes
for node in goodNodes:
print(node + ": BMC Reset Successful")
sys.exit(success)
+22 -7
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/python2
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2015 Lenovo
@@ -17,8 +17,13 @@
import optparse
import os
import signal
import sys
try:
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
except AttributeError:
pass
path = os.path.dirname(os.path.realpath(__file__))
path = os.path.realpath(os.path.join(path, '..', 'lib', 'python'))
if path.startswith('/opt'):
@@ -30,10 +35,17 @@ argparser = optparse.OptionParser()
argparser.add_option('-b', '--bios', dest='biosmode',
action='store_true', default=False,
help='Request BIOS style boot (rather than UEFI)')
argparser.add_option('-u', '--uefi', dest='uefimode',
action='store_true', default=False,
help='Request UEFI style boot (rather than BIOS)')
argparser.add_option('-p', '--persist', dest='persist', action='store_true',
default=False,
help='Request the boot device be persistent rather than '
'one time')
argparser.add_option('-m', '--maxnodes', type='int',
help='Specify a maximum number of '
'nodes to boot, '
'prompting if over the threshold')
(options, args) = argparser.parse_args()
@@ -44,6 +56,7 @@ except IndexError:
'Usage: {0} <noderange> [default|cd|network|setup|hd]\n'.format(
sys.argv[0]))
sys.exit(1)
client.check_globbing(noderange)
bootdev = None
if len(sys.argv) > 2:
bootdev = sys.argv[2]
@@ -56,11 +69,13 @@ if options.biosmode:
else:
bootmode = 'uefi'
errnodes = set([])
session.stop_if_noderange_over(noderange, options.maxnodes)
rc = session.simple_noderange_command(noderange, '/boot/nextdevice', bootdev,
bootmode=bootmode,
persistent=options.persist)
if rc:
sys.exit(rc)
else:
sys.exit(session.simple_noderange_command(noderange, '/power/state', 'boot'))
persistent=options.persist,
errnodes=errnodes)
if errnodes:
noderange = noderange + ',-(' + ','.join(errnodes) + ')'
rc |= session.simple_noderange_command(noderange, '/power/state', 'boot')
sys.exit(rc)
+293
View File
@@ -0,0 +1,293 @@
#!/usr/bin/python2
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2017 Lenovo
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import signal
import optparse
import shlex
import sys
try:
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
except AttributeError:
pass
path = os.path.dirname(os.path.realpath(__file__))
path = os.path.realpath(os.path.join(path, '..', 'lib', 'python'))
if path.startswith('/opt'):
sys.path.append(path)
import confluent.client as client
class NullOpt(object):
blame = None
clear = None
def bailout(msg, code=1):
sys.stderr.write(msg + '\n')
sys.exit(code)
argparser = optparse.OptionParser(usage="Usage: %prog [options] noderange [option|option=value]")
argparser.add_option('-c', '--comparedefault', dest='comparedefault',
action='store_true', default=False,
help='Compare given settings to default or list settings '
'that are non default')
argparser.add_option('-b', '--batch', dest='batch', metavar='settings.batch',
default=False, help='Provide settings in a batch file')
argparser.add_option('-d', '--detail', dest='detail',
action='store_true', default=False,
help='Provide verbose information as available, such as '
'help text and possible valid values')
argparser.add_option('-x', '--exclude', dest='exclude',
action='store_true', default=False,
help='Treat positional arguments as items to not '
'examine, compare, or restore default')
argparser.add_option('-a', '--advanced', dest='advanced',
action='store_true', default=False,
help='Include advanced settings, which are normally not '
'intended to be used without direction from the '
'relevant server vendor.')
argparser.add_option('-r', '--restoredefault', default=False,
dest='restoredefault', metavar="COMPONENT",
help='Restore the configuration of the node '
'to factory default for given component. '
'Currently only uefi is supported')
argparser.add_option('-m', '--maxnodes', type='int',
help='Specify a maximum number of '
'nodes to configure, '
'prompting if over the threshold')
(options, args) = argparser.parse_args()
cfgpaths = {
'bmc.ipv4_address': (
'configuration/management_controller/net_interfaces/management',
'ipv4_address'),
'bmc.ipv4_method': (
'configuration/management_controller/net_interfaces/management',
'ipv4_configuration'),
'bmc.ipv4_gateway': (
'configuration/management_controller/net_interfaces/management',
'ipv4_gateway'),
'bmc.hostname': (
'configuration/management_controller/hostname', 'hostname'),
}
autodeps = {
'bmc.ipv4_address': (('bmc.ipv4_method', 'static'),)
}
try:
noderange = args[0]
except IndexError:
argparser.print_help()
sys.exit(1)
client.check_globbing(noderange)
setmode = None
assignment = {}
queryparms = {}
printsys = []
printbmc = []
printallbmc = False
setsys = {}
forceset = False
needval = None
if len(args) == 1 or options.exclude:
if not options.exclude:
printsys = 'all'
for candidate in cfgpaths:
path, attrib = cfgpaths[candidate]
path = '/noderange/{0}/{1}'.format(noderange, path)
if path not in queryparms:
queryparms[path] = {}
queryparms[path][attrib] = candidate
def _assign_value():
if key not in cfgpaths:
setsys[key] = value
for depkey, depval in autodeps.get(key, []):
assignment[depkey] = depval
assignment[key] = value
def parse_config_line(arguments):
global setmode, printallbmc, forceset, key, value, needval, candidate, path, attrib
for param in arguments:
if param == 'show':
continue # forgive muscle memory of pasu users
if param == 'set':
setmode = True
forceset = True
continue
if needval:
key = needval
needval = None
value = param
_assign_value()
continue
if '=' in param or param[-1] == ':' or forceset:
if setmode is None:
setmode = True
if setmode != True:
bailout('Cannot do set and query in same command')
if '=' in param:
key, _, value = param.partition('=')
_assign_value()
elif param[-1] == ':':
needval = param[:-1]
else:
needval = param
else:
if setmode is None:
setmode = False
if setmode != False:
bailout('Cannot do set and query in same command')
if '.' not in param:
if param == 'bmc':
printallbmc = True
matchedparms = False
for candidate in cfgpaths:
if candidate.startswith('{0}.'.format(param)):
matchedparms = True
if not options.exclude:
path, attrib = cfgpaths[candidate]
path = '/noderange/{0}/{1}'.format(noderange, path)
if path not in queryparms:
queryparms[path] = {}
queryparms[path][attrib] = candidate
else:
try:
del queryparms[path]
except KeyError:
pass
if not matchedparms:
printsys.append(param)
elif param not in cfgpaths:
if param.startswith('bmc.'):
printbmc.append(param.replace('bmc.', ''))
else:
printsys.append(param)
else:
path, attrib = cfgpaths[param]
path = '/noderange/{0}/{1}'.format(noderange, path)
if path not in queryparms:
queryparms[path] = {}
queryparms[path][attrib] = param
if options.batch:
printsys = []
argfile = open(options.batch, 'r')
argset = argfile.readline()
while argset:
try:
argset = argset[:argset.index('#')]
except ValueError:
pass
argset = argset.strip()
if argset:
parse_config_line(shlex.split(argset))
argset = argfile.readline()
else:
parse_config_line(args[1:])
session = client.Command()
rcode = 0
if options.restoredefault:
session.stop_if_noderange_over(noderange, options.maxnodes)
if options.restoredefault.lower() in (
'sys', 'system', 'uefi', 'bios'):
for fr in session.update(
'/noderange/{0}/configuration/system/clear'.format(noderange),
{'clear': True}):
rcode |= client.printerror(fr)
sys.exit(rcode)
elif options.restoredefault.lower() in (
'bmc', 'imm', 'xcc'):
for fr in session.update(
'/noderange/{0}/configuration/management_controller/clear'.format(noderange),
{'clear': True}):
rcode |= client.printerror(fr)
sys.exit(rcode)
else:
sys.stderr.write(
'Unrecognized component to restore defaults: {0}\n'.format(
options.restoredefault))
sys.exit(1)
if setmode:
session.stop_if_noderange_over(noderange, options.maxnodes)
if options.exclude:
sys.stderr.write('Cannot use exclude and assign at the same time\n')
sys.exit(1)
updatebypath = {}
attrnamebypath = {}
for key in assignment:
if key not in cfgpaths:
if key.startswith('bmc.'):
path = 'configuration/management_controller/extended/all'
attrib = key.replace('bmc.', '')
else:
path = 'configuration/system/all'
attrib = key
else:
path, attrib = cfgpaths[key]
if path not in updatebypath:
updatebypath[path] = {}
attrnamebypath[path] = {}
updatebypath[path][attrib] = assignment[key]
attrnamebypath[path][attrib] = key
# well, we want to expand things..
# check ipv4, if requested change method to static
for path in updatebypath:
for fr in session.update('/noderange/{0}/{1}'.format(noderange, path),
updatebypath[path]):
rcode |= client.printerror(fr)
for node in fr.get('databynode', []):
r = fr['databynode'][node]
rcode |= client.printerror(r, node)
if 'value' not in r:
continue
keyval = r['value']
key, val = keyval.split('=')
if key in attrnamebypath[path]:
key = attrnamebypath[path][key]
print('{0}: {1}: {2}'.format(node, key, val))
else:
for path in queryparms:
if options.comparedefault:
continue
rc = client.print_attrib_path(path, session, list(queryparms[path]),
NullOpt(), queryparms[path])
if rc:
sys.exit(rc)
if printbmc or printallbmc:
rcode = client.print_attrib_path(
'/noderange/{0}/configuration/management_controller/extended/all'.format(noderange),
session, printbmc, options, attrprefix='bmc.')
if printsys or options.exclude:
if printsys == 'all':
printsys = []
if (options.comparedefault or printsys == []) and not options.advanced:
path = '/noderange/{0}/configuration/system/all'.format(noderange)
else:
path = '/noderange/{0}/configuration/system/advanced'.format(
noderange)
rcode = client.print_attrib_path(path, session, printsys,
options)
sys.exit(rcode)
+46 -3
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/python2
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2015 Lenovo
@@ -17,7 +17,14 @@
import optparse
import os
import subprocess
import sys
path = os.path.dirname(os.path.realpath(__file__))
path = os.path.realpath(os.path.join(path, '..', 'lib', 'python'))
if path.startswith('/opt'):
sys.path.append(path)
import confluent.client as client
import confluent.sortutil as sortutil
confettypath = os.path.join(os.path.dirname(sys.argv[0]), 'confetty')
argparser = optparse.OptionParser(
@@ -26,9 +33,45 @@ argparser = optparse.OptionParser(
"ctrl-'e', then release ctrl, then 'c', then '?' for a full list. "
"For example, ctrl-'e', then 'c', then '.' will exit the current "
"console")
argparser.add_option('-t', '--tile', action='store_true', default=False,
help='Tile console windows in the terminal')
(options, args) = argparser.parse_args()
if len(args) != 1:
argparser.print_help()
sys.exit(1)
os.execl(confettypath, confettypath, 'start',
'/nodes/{0}/console/session'.format(args[0]))
if options.tile:
null = open('/dev/null', 'w')
nodes = []
sess = client.Command()
for res in sess.read('/noderange/{0}/nodes/'.format(args[0])):
node = res.get('item', {}).get('href', '/').replace('/', '')
if not node:
sys.stderr.write(res.get('error', repr(res)) + '\n')
sys.exit(1)
nodes.append(node)
initial = True
pane = 0
for node in sortutil.natural_sort(nodes):
if initial:
initial = False
subprocess.call(
['tmux', 'new-session', '-d', '-s',
'nodeconsole_{0}'.format(os.getpid()), '-x', '800', '-y',
'800', '{0} -m 5 start /nodes/{1}/console/session'.format(
confettypath, node)])
else:
subprocess.call(['tmux', 'select-pane', '-t', str(pane)])
subprocess.call(['tmux', 'set-option', 'pane-border-status', 'top'], stderr=null)
pane += 1
subprocess.call(
['tmux', 'split', '-h',
'{0} -m 5 start /nodes/{1}/console/session'.format(
confettypath, node)])
subprocess.call(['tmux', 'select-layout', 'tiled'], stdout=null)
subprocess.call(['tmux', 'select-pane', '-t', '0'])
subprocess.call(['tmux', 'set-option', 'pane-border-status', 'top'], stderr=null)
os.execlp('tmux', 'tmux', 'attach', '-t', 'nodeconsole_{0}'.format(
os.getpid()))
else:
os.execl(confettypath, confettypath, 'start',
'/nodes/{0}/console/session'.format(args[0]))
+58
View File
@@ -0,0 +1,58 @@
#!/usr/bin/python2
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2017 Lenovo
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import optparse
import os
import signal
import sys
try:
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
except AttributeError:
pass
path = os.path.dirname(os.path.realpath(__file__))
path = os.path.realpath(os.path.join(path, '..', 'lib', 'python'))
if path.startswith('/opt'):
sys.path.append(path)
import confluent.client as client
argparser = optparse.OptionParser(
usage='''\n %prog noderange attribute1=value1 attribute2=value,...
\n ''')
(options, args) = argparser.parse_args()
requestargs=None
try:
noderange = args[0]
except IndexError:
argparser.print_help()
sys.exit(1)
client.check_globbing(noderange)
session = client.Command()
exitcode = 0
attribs = {'name': noderange}
for arg in args[1:]:
key, val = arg.split('=', 1)
attribs[key] = val
for r in session.create('/noderange/', attribs):
if 'error' in r:
sys.stderr.write(r['error'] + '\n')
exitcode |= 1
if 'created' in r:
print('{0}: created'.format(r['created']))
sys.exit(exitcode)
+360
View File
@@ -0,0 +1,360 @@
#!/usr/bin/python2
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2017 Lenovo
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import csv
import optparse
import os
import sys
import time
path = os.path.dirname(os.path.realpath(__file__))
path = os.path.realpath(os.path.join(path, '..', 'lib', 'python'))
if path.startswith('/opt'):
sys.path.append(path)
import confluent.client as client
import confluent.sortutil as sortutil
defcolumns = ['Node', 'Model', 'Serial', 'UUID', 'Mac Address', 'Type',
'Current IP Addresses']
columnmapping = {
'Node': 'nodename',
'Model': 'modelnumber',
'Serial': 'serialnumber',
'UUID': 'uuid',
'Type': 'types',
'Current IP Addresses': 'ipaddrs',
'IP': 'ipaddrs',
'Bay': 'bay',
'Mac Address': 'macs',
'Mac': 'macs',
'Switch': 'switch',
'Port': 'port',
'Advertised IP': 'otheripaddrs',
'Other IP': 'otheripaddrs',
}
def print_disco(options, session, currmac, outhandler, columns):
procinfo = {}
for tmpinfo in session.read('/discovery/by-mac/{0}'.format(currmac)):
procinfo.update(tmpinfo)
if 'Switch' in columns or 'Port' in columns:
for tmpinfo in session.read(
'/networking/macs/by-mac/{0}'.format(currmac)):
if 'ports' in tmpinfo:
# The api sorts so that the most specific available value
# is last
procinfo.update(tmpinfo['ports'][-1])
record = []
for col in columns:
rawcol = columnmapping[col]
rawval = procinfo.get(rawcol, '')
if isinstance(rawval, list):
record.append(','.join(rawval))
else:
record.append(str(rawval))
outhandler.add_row(record)
def process_header(header):
# normalize likely header titles
fields = []
broken = False
for datum in header:
datum = datum.lower()
if datum.startswith('node') or datum.startswith('name'):
fields.append('node')
elif datum in ('nodegroup', 'nodegroups', 'group', 'groups'):
fields.append('groups')
elif datum.startswith('mac') or datum.startswith('ether'):
fields.append('mac')
elif datum.startswith('serial') or datum in ('sn', 's/n'):
fields.append('serial')
elif datum == 'uuid':
fields.append('uuid')
elif datum in ('bmc', 'imm', 'xcc'):
fields.append('hardwaremanagement.manager')
elif datum in ('bmc gateway', 'xcc gateway', 'imm gateway'):
fields.append('net.bmc.ipv4_gateway')
elif datum in ('bmc_gateway', 'xcc_gateway', 'imm_gateway'):
fields.append('net.bmc.ipv4_gateway')
elif datum in ('bmcuser', 'username', 'user'):
fields.append('secret.hardwaremanagementuser')
elif datum in ('bmcpass', 'password', 'pass'):
fields.append('secret.hardwaremanagementpassword')
else:
print("Unrecognized column name {0}".format(datum))
broken = True
if broken:
sys.exit(1)
return tuple(fields)
def datum_complete(datum):
if 'node' not in datum or not datum['node']:
sys.stderr.write('Nodename is a required field')
return False
provided = set(datum)
required = set(['serial', 'uuid', 'mac'])
for field in provided & required:
if datum[field]:
break
else:
sys.stderr.write('One of the fields "Serial Number", "UUID", or '
'"MAC Address" must be provided')
return False
return True
searchkeys = set(['mac', 'serial', 'uuid'])
def search_record(datum, options, session):
for searchkey in searchkeys:
options.__dict__[searchkey] = None
for searchkey in searchkeys & set(datum):
options.__dict__[searchkey] = datum[searchkey]
return list(list_matching_macs(options, session))
def datum_to_attrib(datum):
for key in ('serial', 'uuid', 'mac'):
try:
del datum[key]
except KeyError:
pass
datum['name'] = datum['node']
del datum['node']
return datum
unique_fields = frozenset(['serial', 'mac', 'uuid'])
def import_csv(options, session):
nodedata = []
unique_data = {}
with open(options.importfile, 'r') as datasrc:
records = csv.reader(datasrc)
fields = process_header(next(records))
for field in fields:
if field in unique_fields:
unique_data[field] = set([])
broken = False
for record in records:
currfields = list(fields)
nodedatum = {}
for datum in record:
currfield = currfields.pop(0)
if currfield in unique_fields:
if datum in unique_data[currfield]:
sys.stderr.write(
"Import contains duplicate values "
"({0} with value {1}\n".format(currfield, datum)
)
sys.exit(1)
unique_data[currfield].add(datum)
nodedatum[currfield] = datum
if not datum_complete(nodedatum):
sys.exit(1)
if not search_record(nodedatum, options, session) and not broken:
blocking_scan(session)
if not search_record(nodedatum, options, session):
sys.stderr.write(
"Could not match the following data: " +
repr(nodedatum) + '\n')
broken = True
nodedata.append(nodedatum)
if broken:
sys.exit(1)
for datum in nodedata:
maclist = search_record(datum, options, session)
datum = datum_to_attrib(datum)
nodename = datum['name']
for res in session.create('/nodes/', datum):
if 'error' in res:
sys.stderr.write(res['error'] + '\n')
continue
elif 'created' in res:
print('Defined ' + res['created'])
else:
print(repr(res))
for mac in maclist:
for res in session.update('/discovery/by-mac/{0}'.format(mac),
{'node': nodename}):
if 'error' in res:
sys.stderr.write(res['error'] + '\n')
continue
elif 'assigned' in res:
print('Discovered ' + res['assigned'])
else:
print(repr(res))
def list_discovery(options, session):
orderby = None
if options.fields:
columns = []
for field in options.fields.split(','):
for cdt in columnmapping:
if cdt.lower().replace(
' ', '') == field.lower().replace(' ', ''):
columns.append(cdt)
else:
columns = defcolumns
if options.order:
for field in columns:
if options.order.lower() == field.lower():
orderby = field
outhandler = client.Tabulator(columns)
for mac in list_matching_macs(options, session):
print_disco(options, session, mac, outhandler, columns)
if options.csv:
outhandler.write_csv(sys.stdout, orderby)
else:
for row in outhandler.get_table(orderby):
print(row)
def clear_discovery(options, session):
for mac in list_matching_macs(options, session):
for res in session.delete('/discovery/by-mac/{0}'.format(mac)):
if 'deleted' in res:
print('Cleared info for {0}'.format(res['deleted']))
else:
print(repr(res))
def list_matching_macs(options, session, node=None):
path = '/discovery/'
if node:
path += 'by-node/{0}/'.format(node)
if options.model:
path += 'by-model/{0}/'.format(options.model)
if options.serial:
path += 'by-serial/{0}/'.format(options.serial)
if options.uuid:
path += 'by-uuid/{0}/'.format(options.uuid)
if options.type:
path += 'by-type/{0}/'.format(options.type)
if options.state:
if options.state == 'unknown':
options.state = 'unidentified'
path += 'by-state/{0}/'.format(options.state).lower()
if options.mac:
path += 'by-mac/{0}'.format(options.mac)
result = list(session.read(path))[0]
if 'error' in result:
return []
return [options.mac.replace(':', '-')]
else:
path += 'by-mac/'
return [x['item']['href'] for x in session.read(path)]
def assign_discovery(options, session, needid=True):
abort = False
if options.importfile:
return import_csv(options, session)
if not options.node:
sys.stderr.write("Node (-n) must be specified for assignment\n")
abort = True
if needid and not (options.serial or options.uuid or options.mac):
sys.stderr.write(
"UUID (-u), serial (-s), or ether address (-e) required for "
"assignment\n")
abort = True
if abort:
sys.exit(1)
matches = list_matching_macs(options, session, None if needid else options.node)
if not matches:
# Do a rescan to catch missing requested data
blocking_scan(session)
matches = list_matching_macs(options, session, None if needid else options.node)
if not matches:
sys.stderr.write("No matching discovery candidates found\n")
sys.exit(1)
for res in session.update('/discovery/by-mac/{0}'.format(matches[0]),
{'node': options.node}):
if 'assigned' in res:
print('Assigned: {0}'.format(res['assigned']))
else:
print(repr(res))
def blocking_scan(session):
list(session.update('/discovery/rescan', {'rescan': 'start'}))
while(list(session.read('/discovery/rescan'))[0].get('scanning', False)):
time.sleep(0.5)
list(session.update('/networking/macs/rescan', {'rescan': 'start'}))
def main():
parser = optparse.OptionParser(
usage='Usage: %prog [list|assign|rescan|clear] [options]')
# -a for 'address' maybe?
# order by
# show state (discovered or..
# nodediscover approve?
# flush to clear old data out? (e.g. no good way to age pxe data)
# also delete discovery datum... more targeted
# defect: -t lenovo-imm returns all
parser.add_option('-m', '--model', dest='model',
help='Operate with nodes matching the specified model '
'number', metavar='MODEL')
parser.add_option('-d', '--discoverystate', dest='state',
help='The discovery state of the entries (discovered, '
'identified, and unidentified)')
parser.add_option('-s', '--serial', dest='serial',
help='Operate against the system matching the specified '
'serial number', metavar='SERIAL')
parser.add_option('-u', '--uuid', dest='uuid',
help='Operate against the system matching the specified '
'UUID', metavar='UUID')
parser.add_option('-n', '--node', help='Operate with the given nodename')
parser.add_option('-e', '--ethaddr', dest='mac',
help='Operate against the system with the specified MAC '
'address', metavar='MAC')
parser.add_option('-t', '--type', dest='type',
help='Operate against the system of the specified type',
metavar='TYPE')
parser.add_option('-c', '--csv', dest='csv',
help='Use CSV formatted output', action='store_true')
parser.add_option('-i', '--import', dest='importfile',
help='Import bulk assignment data from given CSV file',
metavar='IMPORT.CSV')
parser.add_option('-f', '--fields', dest='fields',
help='Select fields for output',
metavar='FIELDS')
parser.add_option('-o', '--order', dest='order',
help='Order output by given field', metavar='ORDER')
(options, args) = parser.parse_args()
if len(args) == 0 or args[0] not in ('list', 'assign', 'reassign', 'rescan', 'clear'):
parser.print_help()
sys.exit(1)
session = client.Command()
if args[0] == 'list':
list_discovery(options, session)
if args[0] == 'clear':
clear_discovery(options, session)
if args[0] == 'assign':
assign_discovery(options, session)
if args[0] == 'reassign':
assign_discovery(options, session, False)
if args[0] == 'rescan':
blocking_scan(session)
print("Rescan complete")
if __name__ == '__main__':
main()
+33 -8
View File
@@ -1,7 +1,7 @@
#!/usr/bin/python
#!/usr/bin/python2
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2015-2017 Lenovo
# Copyright 2015-2019 Lenovo
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,11 +15,17 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import codecs
from datetime import datetime as dt
import optparse
import os
import signal
import sys
try:
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
except AttributeError:
pass
path = os.path.dirname(os.path.realpath(__file__))
path = os.path.realpath(os.path.join(path, '..', 'lib', 'python'))
if path.startswith('/opt'):
@@ -27,19 +33,32 @@ if path.startswith('/opt'):
import confluent.client as client
if sys.version_info[0] < 3:
sys.stdout = codecs.getwriter('utf8')(sys.stdout)
argparser = optparse.OptionParser(
usage="Usage: %prog [options] noderange (clear)")
usage="Usage: %prog [options] noderange [clear]")
argparser.add_option('-m', '--maxnodes', type='int',
help='Specify a maximum number of '
'nodes to clear if clearing log, '
'prompting if over the threshold')
(options, args) = argparser.parse_args()
try:
noderange = args[0]
except IndexError:
argparser.print_help()
sys.exit(1)
client.check_globbing(noderange)
deletemode = False
if len(sys.argv) == 3:
if sys.argv[2] == 'clear':
if len(args) > 2:
argparser.print_help()
sys.exit(1)
if len(args) == 2:
if args[1] == 'clear':
deletemode = True
else:
argparser.print_help()
sys.exit(1)
session = client.Command()
exitcode = 0
@@ -50,6 +69,8 @@ def format_event(evt):
display = dt.strptime(evt['timestamp'], '%Y-%m-%dT%H:%M:%S')
retparts.append(display.strftime('%m/%d/%Y %H:%M:%S'))
dscparts = []
if evt.get('log_id', None):
retparts.append(evt['log_id'] + ':')
if 'component_type' in evt and evt['component_type'] is not None:
dscparts.append(evt['component_type'])
if 'component' in evt and evt['component'] is not None:
@@ -63,11 +84,15 @@ def format_event(evt):
pass
dscparts.append(evttext)
retparts.append(' - '.join(dscparts))
return ' '.join(retparts)
msg = evt.get('message')
if not msg:
msg = ''
return ' '.join(retparts) + msg
if deletemode:
func = session.delete
session.stop_if_noderange_over(noderange, options.maxnodes)
else:
func = session.read
for rsp in func('/noderange/{0}/events/hardware/log'.format(noderange)):
@@ -84,4 +109,4 @@ for rsp in func('/noderange/{0}/events/hardware/log'.format(noderange)):
if 'events' in thisdata:
evtdata = thisdata['events']
for evt in evtdata:
print '{0}: {1}'.format(node, format_event(evt))
print('{0}: {1}'.format(node, format_event(evt)))
+119 -32
View File
@@ -1,4 +1,4 @@
#!/usr/bin/python
#!/usr/bin/python2
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2016-2017 Lenovo
@@ -17,39 +17,34 @@
import optparse
import os
import signal
import sys
import time
try:
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
except AttributeError:
pass
path = os.path.dirname(os.path.realpath(__file__))
path = os.path.realpath(os.path.join(path, '..', 'lib', 'python'))
if path.startswith('/opt'):
sys.path.append(path)
import confluent.client as client
import confluent.screensqueeze as sq
exitcode = 0
def printerror(res, node=None):
global exitcode
if 'errorcode' in res:
exitcode = res['errorcode']
if 'error' in res:
if node:
sys.stderr.write('{0}: {1}\n'.format(node, res['error']))
else:
sys.stderr.write('{0}\n'.format(res['error']))
if 'errorcode' not in res:
exitcode = 1
def printfirm(node, prefix, data):
if 'model' in data:
if 'model' in data and data['model']:
prefix += ' ' + data['model']
builddesc = []
if 'build' in data:
if 'build' in data and data['build']:
builddesc.append(data['build'])
if 'date' in data:
if 'date' in data and data['date']:
builddesc.append(data['date'])
if 'version' in data:
if 'version' in data and data['version']:
version = data['version']
if builddesc:
version += ' ({0})'.format(' '.join(builddesc))
@@ -57,28 +52,120 @@ def printfirm(node, prefix, data):
version = ' '.join(builddesc)
print('{0}: {1}: {2}'.format(node, prefix, version))
components = ['all']
argparser = optparse.OptionParser(usage="Usage: %prog <noderange>")
argparser = optparse.OptionParser(
usage="Usage: "
"%prog <noderange> [list][update [--backup <file>]]|[<components>]")
argparser.add_option('-b', '--backup', action='store_true',
help='Target a backup bank rather than primary')
argparser.add_option('-m', '--maxnodes', type='int',
help='When updating, prompt if more than the specified '
'number of servers will be affected')
(options, args) = argparser.parse_args()
upfile = None
try:
noderange = args[0]
if len(args) > 1:
if args[1] == 'update':
upfile = args[2]
else:
if args[1] == 'list':
comps = args[2:]
else:
comps = args[1:]
components = []
for arg in comps:
components += arg.split(',')
if not components:
components = ['all']
except IndexError:
argparser.print_help()
sys.exit(1)
client.check_globbing(noderange)
def get_update_progress(session, url):
for res in session.read(url):
status = res['phase']
percent = res['progress']
detail = res['detail']
if status == 'error':
text = 'error!'
else:
text = '{0}: {1:3.0f}%'.format(status, percent)
return text, status, detail
def update_firmware(session, filename):
global exitcode
session.stop_if_noderange_over(noderange, options.maxnodes)
output = sq.ScreenPrinter(noderange, session)
nodeurls = {}
filename = os.path.abspath(filename)
resource = '/noderange/{0}/inventory/firmware/updates/active'.format(
noderange)
upargs = {'filename': filename}
if options.backup:
upargs['bank'] = 'backup'
noderrs = {}
for res in session.create(resource, upargs):
if 'created' not in res:
for nodename in res.get('databynode', ()):
output.set_output(nodename, 'error!')
noderrs[nodename] = res['databynode'][nodename].get(
'error', 'Unknown Error')
continue
watchurl = res['created']
currnode = watchurl.split('/')[1]
nodeurls[currnode] = '/' + watchurl
while nodeurls:
for node in list(nodeurls):
progress, status, err = get_update_progress(
session, nodeurls[node])
if status == 'error':
exitcode = 1
noderrs[node] = err
if status in ('error', 'complete', 'pending'):
list(session.delete(nodeurls[node]))
del nodeurls[node]
output.set_output(node, progress)
time.sleep(2)
allerrnodes = ','.join(noderrs)
if noderrs:
sys.stderr.write(
'Nodes had errors updating ({0})!\n'.format(allerrnodes))
for node in noderrs:
sys.stderr.write('{0}: {1}\n'.format(node, noderrs[node]))
def show_firmware(session):
global exitcode
firmware_shown = False
for component in components:
for res in session.read(
'/noderange/{0}/inventory/firmware/all/{1}'.format(
noderange, component)):
exitcode |= client.printerror(res)
if 'databynode' not in res:
continue
for node in res['databynode']:
exitcode |= client.printerror(res['databynode'][node], node)
if 'firmware' not in res['databynode'][node]:
continue
for inv in res['databynode'][node]['firmware']:
for prefix in inv:
firmware_shown = True
printfirm(node, prefix, inv[prefix])
if not firmware_shown and not exitcode:
argparser.print_help()
try:
session = client.Command()
for res in session.read('/noderange/{0}/inventory/firmware/all/all'.format(
noderange)):
printerror(res)
if 'databynode' not in res:
continue
for node in res['databynode']:
printerror(res['databynode'][node], node)
if 'firmware' not in res['databynode'][node]:
continue
for inv in res['databynode'][node]['firmware']:
for prefix in inv:
printfirm(node, prefix, inv[prefix])
if upfile is None:
show_firmware(session)
else:
update_firmware(session, upfile)
except KeyboardInterrupt:
print('')
sys.exit(exitcode)
sys.exit(exitcode)
+38 -8
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/python2
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2017 Lenovo
@@ -17,10 +17,16 @@
__author__ = 'alin37'
from getpass import getpass
import optparse
import os
import signal
import sys
try:
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
except AttributeError:
pass
path = os.path.dirname(os.path.realpath(__file__))
path = os.path.realpath(os.path.join(path, '..', 'lib', 'python'))
if path.startswith('/opt'):
@@ -30,14 +36,20 @@ import confluent.client as client
argparser = optparse.OptionParser(
usage='''\n %prog [options] \
\n %prog [options] nodegroup [list of attributes] \
\n %prog [options] nodegroup group=value1,value2 \
\n %prog [options] nodegroup group=value1,value2
\n %prog [options] nodegroup [list of attributes|all] \
\n %prog [options] nodegroup nodes=value1,value2 \
\n %prog -e nodegroup <attribute names to set> \
\n %prog [options] nodegroup nodes=value1,value2
\n ''')
argparser.add_option('-b', '--blame', action='store_true',
help='Show information about how attributes inherited')
argparser.add_option('-e', '--environment', action='store_true',
help='Set attributes, but from environment variable of '
'same name')
argparser.add_option('-c', '--clear', action='store_true',
help='Clear variables')
argparser.add_option('-p', '--prompt', action='store_true',
help='Prompt for attribute values interactively')
(options, args) = argparser.parse_args()
@@ -51,13 +63,31 @@ try:
nodelist = '/{0}/{1}/'.format(nodetype,nodegroups)
except IndexError:
nodelist = '/nodegroups/'
client.check_globbing(nodegroups)
session = client.Command()
exitcode = 0
#Sets attributes
if len(args) > 1:
exitcode=client.updateattrib(session,args,nodetype, nodegroups, options)
showtype = 'all'
if "=" in args[1] and options.clear:
print("Can not clear and set at the same time!")
argparser.print_help()
sys.exit(1)
argassign = None
if options.prompt:
argassign = {}
for arg in args[1:]:
oneval = 1
twoval = 2
while oneval != twoval:
oneval = getpass('Enter value for {0}: '.format(arg))
twoval = getpass('Confirm value for {0}: '.format(arg))
if oneval != twoval:
print('Values did not match.')
argassign[arg] = twoval
exitcode=client.updateattrib(session,args,nodetype, nodegroups, options, argassign)
try:
# setting user output to what the user inputs
if args[1] == 'all':
@@ -67,7 +97,7 @@ if len(args) > 1:
requestargs=args[1:]
except Exception as e:
print str(e)
print(str(e))
if exitcode != 0:
sys.exit(exitcode)
@@ -93,6 +123,6 @@ else:
sys.stderr.write(res['error'] + '\n')
exitcode = 1
else:
print res['item']['href'].replace('/', '')
print(res['item']['href'].replace('/', ''))
sys.exit(exitcode)
sys.exit(exitcode)
+58
View File
@@ -0,0 +1,58 @@
#!/usr/bin/python2
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2017 Lenovo
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import optparse
import os
import signal
import sys
try:
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
except AttributeError:
pass
path = os.path.dirname(os.path.realpath(__file__))
path = os.path.realpath(os.path.join(path, '..', 'lib', 'python'))
if path.startswith('/opt'):
sys.path.append(path)
import confluent.client as client
argparser = optparse.OptionParser(
usage='''\n %prog noderange attribute1=value1 attribute2=value,...
\n ''')
(options, args) = argparser.parse_args()
requestargs=None
try:
noderange = args[0]
except IndexError:
argparser.print_help()
sys.exit(1)
client.check_globbing(noderange)
session = client.Command()
exitcode = 0
attribs = {'name': noderange}
for arg in args[1:]:
key, val = arg.split('=', 1)
attribs[key] = val
for r in session.create('/nodegroups/', attribs):
if 'error' in r:
sys.stderr.write(r['error'] + '\n')
exitcode |= 1
if 'created' in r:
print('{0}: created'.format(r['created']))
sys.exit(exitcode)
+62
View File
@@ -0,0 +1,62 @@
#!/usr/bin/python2
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2015-2017 Lenovo
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
__author__ = 'jjohnson2,alin37,andywray'
import optparse
import os
import signal
import sys
try:
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
except AttributeError:
pass
path = os.path.dirname(os.path.realpath(__file__))
path = os.path.realpath(os.path.join(path, '..', 'lib', 'python'))
if path.startswith('/opt'):
sys.path.append(path)
import confluent.client as client
def main():
argparser = optparse.OptionParser(
usage="Usage: %prog\n")
(options, args) = argparser.parse_args()
noderange=""
nodelist=""
nodelist = '/nodegroups/'
session = client.Command()
exitcode = 0
showtype='all'
requestargs=args[1:]
nodetype='noderange'
if len(args) > 0:
argparser.print_help()
sys.exit(1)
else:
for res in session.read(nodelist):
if 'error' in res:
sys.stderr.write(res['error'] + '\n')
exitcode = 1
else:
print(res['item']['href'].replace('/', ''))
sys.exit(exitcode)
if __name__ == '__main__':
main()
+52
View File
@@ -0,0 +1,52 @@
#!/usr/bin/python2
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2017 Lenovo
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import optparse
import os
import signal
import sys
try:
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
except AttributeError:
pass
path = os.path.dirname(os.path.realpath(__file__))
path = os.path.realpath(os.path.join(path, '..', 'lib', 'python'))
if path.startswith('/opt'):
sys.path.append(path)
import confluent.client as client
argparser = optparse.OptionParser(
usage='''\n %prog noderange
\n ''')
(options, args) = argparser.parse_args()
if len(args) != 1:
argparser.print_help()
sys.exit(1)
noderange = args[0]
client.check_globbing(noderange)
session = client.Command()
exitcode = 0
for r in session.delete('/nodegroups/{0}'.format(noderange)):
if 'error' in r:
sys.stderr.write(r['error'] + '\n')
exitcode |= 1
if 'deleted' in r:
print('{0}: deleted'.format(r['deleted']))
sys.exit(exitcode)
+63
View File
@@ -0,0 +1,63 @@
#!/usr/bin/python2
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2019 Lenovo
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
__author__ = 'jjohnson2,alin37,andywray'
import optparse
import os
import signal
import sys
try:
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
except AttributeError:
pass
path = os.path.dirname(os.path.realpath(__file__))
path = os.path.realpath(os.path.join(path, '..', 'lib', 'python'))
if path.startswith('/opt'):
sys.path.append(path)
import confluent.client as client
def main():
argparser = optparse.OptionParser(
usage="Usage: %prog <group> <new group name>\n")
(options, args) = argparser.parse_args()
noderange=""
nodelist=""
nodelist = '/nodegroups/'
session = client.Command()
exitcode = 0
requestargs=args[1:]
nodetype='noderange'
if len(args) != 2:
argparser.print_help()
sys.exit(1)
else:
for res in session.update(
'/nodegroups/{0}/attributes/rename'.format(args[0]),
{'rename': args[1]}):
if 'error' in res:
sys.stderr.write(res['error'] + '\n')
exitcode = 1
else:
print('{0}: {1}'.format(res['oldname'], res['newname']))
sys.exit(exitcode)
if __name__ == '__main__':
main()
+20 -4
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/python2
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2015-2017 Lenovo
@@ -18,8 +18,13 @@
import codecs
import optparse
import os
import signal
import sys
try:
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
except AttributeError:
pass
path = os.path.dirname(os.path.realpath(__file__))
path = os.path.realpath(os.path.join(path, '..', 'lib', 'python'))
if path.startswith('/opt'):
@@ -27,7 +32,8 @@ if path.startswith('/opt'):
import confluent.client as client
sys.stdout = codecs.getwriter('utf8')(sys.stdout)
if sys.version_info[0] < 3:
sys.stdout = codecs.getwriter('utf8')(sys.stdout)
argparser = optparse.OptionParser(usage="Usage: %prog <noderange>")
(options, args) = argparser.parse_args()
@@ -36,8 +42,16 @@ try:
except IndexError:
argparser.print_help()
sys.exit(1)
client.check_globbing(noderange)
codemappings = {
'ok': 0,
'warning': 1,
'critical': 2,
'failed': 2,
}
def main():
global session, exitcode, healthbynode, healthexplanations, health, node, sensor, explanation
session = client.Command()
@@ -60,9 +74,11 @@ def main():
if 'error' in health[node]:
sys.stderr.write('{0}: Error: {1}\n'.format(
node, health[node]['error']))
exitcode |= 1
exitcode = 3
if 'health' in health[node]:
healthbynode[node] = health[node]['health']['value']
if codemappings[healthbynode[node]] > exitcode:
exitcode = codemappings[healthbynode[node]]
if 'sensors' in health[node]:
healthexplanations[node] = []
for sensor in health[node]['sensors']:
@@ -88,5 +104,5 @@ try:
main()
except KeyboardInterrupt:
print('')
sys.exit(0)
sys.exit(exitcode)
+8 -6
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/python2
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2015-2017 Lenovo
@@ -17,7 +17,12 @@
import optparse
import os
import signal
import sys
try:
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
except AttributeError:
pass
path = os.path.dirname(os.path.realpath(__file__))
path = os.path.realpath(os.path.join(path, '..', 'lib', 'python'))
@@ -26,20 +31,17 @@ if path.startswith('/opt'):
import confluent.client as client
argparser = optparse.OptionParser(usage="Usage: %prog <noderange> [on|off]")
argparser = optparse.OptionParser(usage="Usage: %prog <noderange> [on|off|blink]")
(options, args) = argparser.parse_args()
try:
noderange = args[0]
except IndexError:
argparser.print_help()
sys.exit(1)
client.check_globbing(noderange)
identifystate = None
if len(sys.argv) > 2:
identifystate = sys.argv[2]
else:
argparser.print_help()
sys.exit(1)
session = client.Command()
exitcode = 0
sys.exit(
+91 -16
View File
@@ -1,4 +1,4 @@
#!/usr/bin/python
#!/usr/bin/python2
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2016-2017 Lenovo
@@ -15,9 +15,18 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import codecs
import json
import optparse
import os
import re
import signal
import sys
try:
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
except AttributeError:
pass
path = os.path.dirname(os.path.realpath(__file__))
path = os.path.realpath(os.path.join(path, '..', 'lib', 'python'))
if path.startswith('/opt'):
@@ -25,6 +34,11 @@ if path.startswith('/opt'):
import confluent.client as client
if sys.version_info[0] < 3:
sys.stdout = codecs.getwriter('utf8')(sys.stdout)
filters = []
def pretty(text):
if text == 'pcislot':
@@ -34,15 +48,20 @@ def pretty(text):
return text
def print_mem_info(node, prefix, meminfo):
capacity = meminfo['capacity_mb'] / 1024
memdescfmt = '{0}GB PC'
if meminfo['memory_type'] == 'DDR3 SDRAM':
memdescfmt += '3-{1} '
elif meminfo['memory_type'] == 'DDR4 SDRAM':
elif 'DDR4' in meminfo['memory_type']:
memdescfmt += '4-{1} '
if meminfo['ecc']:
else:
print('{0}: {1}: Unrecognized Memory'.format(node, prefix))
return
if meminfo.get('ecc', False):
memdescfmt += 'ECC '
memdescfmt += meminfo['module_type']
capacity = meminfo['capacity_mb'] / 1024
modtype = meminfo.get('module_type', None)
if modtype:
memdescfmt += modtype
memdesc = memdescfmt.format(capacity, meminfo['speed'])
print('{0}: {1} description: {2}'.format(node, prefix, memdesc))
print('{0}: {1} manufacturer: {2}'.format(
@@ -50,10 +69,11 @@ def print_mem_info(node, prefix, meminfo):
print('{0}: {1} model: {2}'.format(node, prefix, meminfo['model']))
print('{0}: {1} serial number: {2}'.format(node, prefix,
meminfo['serial']))
print('{0}: {1} manufacture date: {2}'.format(node, prefix,
meminfo['manufacture_date']))
print('{0}: {1} manufacture location: {2}'.format(
node, prefix, meminfo['manufacture_location']))
if 'manufacture_date' in meminfo:
print('{0}: {1} manufacture date: {2}'.format(node, prefix,
meminfo['manufacture_date']))
print('{0}: {1} manufacture location: {2}'.format(
node, prefix, meminfo['manufacture_location']))
exitcode = 0
@@ -70,17 +90,41 @@ def printerror(res, node=None):
exitcode = 1
argparser = optparse.OptionParser(usage="Usage: %prog <noderange>")
url = '/noderange/{0}/inventory/hardware/all/all'
usedprefixes = set([])
argparser = optparse.OptionParser(
usage="Usage: %prog <noderange> [serial|model|uuid|mac]")
argparser.add_option('-j', '--json', action='store_true', help='Output JSON')
(options, args) = argparser.parse_args()
try:
noderange = sys.argv[1]
noderange = args[0]
except IndexError:
argparser.print_help()
sys.exit(1)
client.check_globbing(noderange)
if len(args) > 1:
if args[1] == 'firm':
os.execlp('nodefirmware', 'nodefirmware', noderange)
else:
url = '/noderange/{0}/inventory/hardware/all/system'
for arg in args:
for arg in arg.split(','):
if arg == 'serial':
filters.append(re.compile('serial number'))
elif arg == 'model':
filters.append(re.compile('^model'))
filters.append(re.compile('product name'))
elif arg == 'uuid':
filters.append(re.compile('uuid'))
elif arg == 'mac':
filters.append(re.compile('mac address'))
url = '/noderange/{0}/inventory/hardware/all/all'
try:
if options.json:
databynode = {}
session = client.Command()
for res in session.read('/noderange/{0}/inventory/hardware/all/all'.format(
noderange)):
for res in session.read(url.format(noderange)):
printerror(res)
if 'databynode' not in res:
continue
@@ -90,8 +134,19 @@ try:
continue
for inv in res['databynode'][node]['inventory']:
prefix = inv['name']
idx = 2
while (node, prefix) in usedprefixes:
prefix = '{0} {1}'.format(inv['name'], idx)
idx += 1
usedprefixes.add((node, prefix))
if not inv['present']:
print '{0}: {1}: Not Present'.format(node, prefix)
if not filters:
if options.json:
if node not in databynode:
databynode[node] = {}
databynode[node][prefix] = inv
else:
print('{0}: {1}: Not Present'.format(node, prefix))
continue
info = inv['information']
info.pop('board_extra', None)
@@ -99,14 +154,34 @@ try:
info.pop('chassis_extra', None)
info.pop('product_extra', None)
if 'memory_type' in info:
print_mem_info(node, prefix, info)
if not filters:
if options.json:
if node not in databynode:
databynode[node] = {}
databynode[node][prefix] = inv
continue
print_mem_info(node, prefix, info)
continue
for datum in info:
if filters:
for filter in filters:
if filter.match(datum.lower()):
break
else:
continue
if info[datum] is None:
continue
if options.json:
if node not in databynode:
databynode[node] = {}
databynode[node][prefix] = inv
break
print(u'{0}: {1} {2}: {3}'.format(node, prefix,
pretty(datum),
info[datum]))
if options.json:
print(json.dumps(databynode, sort_keys=True, indent=4,
separators=(',', ': ')))
except KeyboardInterrupt:
print('')
sys.exit(exitcode)
sys.exit(exitcode)
+151
View File
@@ -0,0 +1,151 @@
#!/usr/bin/python2
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2019 Lenovo
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import optparse
import os
import signal
import sys
import time
try:
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
except AttributeError:
pass
path = os.path.dirname(os.path.realpath(__file__))
path = os.path.realpath(os.path.join(path, '..', 'lib', 'python'))
if path.startswith('/opt'):
sys.path.append(path)
import confluent.client as client
exitcode = 0
argparser = optparse.OptionParser(
usage="Usage: "
"%prog <noderange> [list][install <file>|save <directory>|delete <name>]")
argparser.add_option('-m', '--maxnodes', type='int',
help='Specify a maximum number of '
'nodes to delete licenses from, '
'prompting if over the threshold')
(options, args) = argparser.parse_args()
upfile = None
downdir = None
delete = False
try:
noderange = args[0]
if len(args) > 1:
if args[1] == 'install':
upfile = args[2]
elif args[1] == 'save':
downdir = args[2]
elif args[1] == 'delete':
delete = args[2]
elif args[1] != 'list':
argparser.print_help()
sys.exit(1)
except IndexError:
argparser.print_help()
sys.exit(1)
client.check_globbing(noderange)
def install_license(session, filename):
global exitcode
if not os.path.exists(filename):
sys.stderr.write('Unable to locate requested file {0}\n'.format(
filename))
sys.exit(404)
resource = '/noderange/{0}/configuration/' \
'management_controller/licenses/'.format(noderange)
filename = os.path.abspath(filename)
instargs = {'filename': filename}
for res in session.create(resource, instargs):
for node in res.get('databynode', []):
if 'error' in res['databynode'][node]:
sys.stderr.write('{0}: {1}\n'.format(
node, res['databynode'][node]['error']))
sys.exit(res['databynode'][node].get('errorcode', 1))
show_licenses(session)
def save_licenses(session, dirname):
global exitcode
resource = '/noderange/{0}/configuration/' \
'management_controller/save_licenses'.format(noderange)
filename = os.path.abspath(dirname)
if not os.path.exists(filename):
sys.stderr.write('Unable to locate specified directory {0}\n'.format(
filename))
sys.exit(404)
instargs = {'dirname': filename}
for res in session.create(resource, instargs):
for node in res.get('databynode', {}):
fname = res['databynode'][node].get('filename', None)
if fname:
print('{0}: Saved license to {1}'.format(node, fname))
else:
sys.stderr.write('{0}: {1}', node, repr(res['databynode'][node]))
def show_licenses(session):
global exitcode
for res in session.read(
'/noderange/{0}/configuration/management_controller/licenses/'
'all'.format(noderange)):
for node in res.get('databynode', {}):
for license in res['databynode'][node].get('License', []):
msg = '{0}: {1}'.format(node, license.get('feature',
'Unknown'))
if license.get('state', 'Active') != 'Active':
msg += ' ({0})'.format(license['state'])
print(msg)
def delete_license(session, licname):
global exitcode
licstodel = []
for res in list(session.read(
'/noderange/{0}/configuration/management_controller/licenses/'
'all'.format(noderange))):
for node in res.get('databynode', {}):
for license in res['databynode'][node].get('License', []):
if license.get('feature', None) == licname:
prefix = '/nodes/{0}/configuration/management_controller/licenses/'.format(node)
for currlic in list(session.read(prefix)):
currlic = currlic.get('item', {}).get('href', 'all')
if currlic == 'all':
continue
currname = list(session.read(prefix + currlic))[0]
currname = currname.get('License', [{}])[0].get('feature', None)
if currname == licname:
list(session.delete(prefix + currlic))
show_licenses(session)
try:
session = client.Command()
if upfile:
install_license(session, upfile)
elif downdir:
save_licenses(session, downdir)
elif delete:
session.stop_if_noderange_over(noderange, options.maxnodes)
delete_license(session, delete)
else:
show_licenses(session)
except KeyboardInterrupt:
print('')
sys.exit(exitcode)
+11 -4
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/python2
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2015-2017 Lenovo
@@ -19,8 +19,13 @@ __author__ = 'jjohnson2,alin37'
import optparse
import os
import signal
import sys
try:
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
except AttributeError:
pass
path = os.path.dirname(os.path.realpath(__file__))
path = os.path.realpath(os.path.join(path, '..', 'lib', 'python'))
if path.startswith('/opt'):
@@ -30,7 +35,8 @@ import confluent.client as client
def main():
argparser = optparse.OptionParser(
usage="Usage: %prog [options] noderange [list of attributes]")
usage="Usage: %prog noderange\n"
" or: %prog [options] noderange <nodeattribute>...")
argparser.add_option('-b', '--blame', action='store_true',
help='Show information about how attributes inherited')
(options, args) = argparser.parse_args()
@@ -41,6 +47,7 @@ def main():
nodelist = '/noderange/{0}/nodes/'.format(noderange)
except IndexError:
nodelist = '/nodes/'
client.check_globbing(noderange)
session = client.Command()
exitcode = 0
showtype='all'
@@ -54,9 +61,9 @@ def main():
sys.stderr.write(res['error'] + '\n')
exitcode = 1
else:
print res['item']['href'].replace('/', '')
print(res['item']['href'].replace('/', ''))
sys.exit(exitcode)
if __name__ == '__main__':
main()
main()
+191
View File
@@ -0,0 +1,191 @@
#!/usr/bin/python2
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2018 Lenovo
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import optparse
import os
import signal
import sys
import time
try:
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
except AttributeError:
pass
path = os.path.dirname(os.path.realpath(__file__))
path = os.path.realpath(os.path.join(path, '..', 'lib', 'python'))
if path.startswith('/opt'):
sys.path.append(path)
import confluent.client as client
import confluent.screensqueeze as sq
exitcode = 0
def get_update_progress(session, url):
for res in session.read(url):
status = res['phase']
percent = res['progress']
detail = res['detail']
if status == 'error':
text = 'error!'
else:
text = '{0}: {1:3.0f}%'.format(status, percent)
return text, status, detail
def printerror(res, node=None):
global exitcode
if 'errorcode' in res:
exitcode = res['errorcode']
if 'error' in res:
if node:
sys.stderr.write('{0}: {1}\n'.format(node, res['error']))
else:
sys.stderr.write('{0}\n'.format(res['error']))
if 'errorcode' not in res:
exitcode = 1
for node in res.get('databynode', ()):
printerror(res['databynode'][node], node)
def attach_media(noderange, media):
global exitcode
session = client.Command()
if ':' not in media:
sys.stderr.write('Full URL required for attach\n')
sys.exit(1)
resource = '/noderange/{0}/media/attach'.format(noderange)
for res in session.update(resource, {'url': media}):
printerror(res)
list_media(noderange, media)
def list_media(noderange, media):
session = client.Command()
resource = '/noderange/{0}/media/current'.format(noderange)
for res in session.read(resource):
printerror(res)
for node in res.get('databynode', []):
url = res['databynode'][node].get('url', None)
name = res['databynode'][node].get('name', None)
if (url and not url.startswith('file:') and
not res['databynode'][node].get('secure', False)):
name += ' (insecure)'
if not name:
continue
print('{0}: {1}'.format(node, url + '/' + name if url else name))
def detach_media(noderange, media):
global exitcode
session = client.Command()
resource = '/noderange/{0}/media/detach'.format(noderange)
for res in session.update(resource, {'detachall': 1}):
printerror(res)
def upload_media(noderange, media):
global exitcode
if not os.path.exists(media):
sys.stderr.write('Unable to locate requested file {0}\n'.format(
media))
sys.exit(404)
session = client.Command()
output = sq.ScreenPrinter(noderange, session)
filename = os.path.abspath(media)
resource = '/noderange/{0}/media/uploads/'.format(noderange)
upargs = {'filename': filename}
noderrs = {}
nodeurls = {}
for res in session.create(resource, upargs):
if 'created' not in res:
for nodename in res.get('databynode', ()):
output.set_output(nodename, 'error!')
noderrs[nodename] = res['databynode'][nodename].get(
'error', 'Unknown Error')
continue
watchurl = res['created']
currnode = watchurl.split('/')[1]
nodeurls[currnode] = '/' + watchurl
while nodeurls:
for node in list(nodeurls):
progress, status, err = get_update_progress(
session, nodeurls[node])
if status == 'error':
exitcode = 1
noderrs[node] = err
if status in ('error', 'complete', 'pending'):
list(session.delete(nodeurls[node]))
del nodeurls[node]
output.set_output(node, progress)
time.sleep(2)
allerrnodes = ','.join(noderrs)
if noderrs:
sys.stderr.write(
'Nodes had errors receiving media ({0})!\n'.format(allerrnodes))
for node in noderrs:
sys.stderr.write('{0}: {1}\n'.format(node, noderrs[node]))
list_media(noderange, media)
funmap = {
'upload': upload_media,
'attach': attach_media,
'detachall': detach_media,
'list': list_media,
}
class OptParser(optparse.OptionParser):
def format_epilog(self, formatter):
return self.expand_prog_name(self.epilog)
def main():
argparser = OptParser(
usage="Usage: %prog <noderange> [list|upload|attach|detachall] "
"<filename>|all|<url>",
epilog='\nupload will take the specified file and upload it to the '
'BMC.\n\n'
'attach will instruct the BMC to connect a remote media to the '
'specified url.\n\ndetachall will remove *ALL* uploaded and '
'attached urls from the BMC\n\nlist shows currently mounted '
'media.\n\nSee `man %prog` for more info.\n')
(options, args) = argparser.parse_args()
media = None
try:
noderange = args[0]
operation = args[1]
arglength = 2
if operation in ('attach', 'upload'):
media = args[2]
arglength = 3
if len(args) > arglength:
argparser.print_help()
sys.exit(1)
except IndexError:
argparser.print_help()
sys.exit(1)
client.check_globbing(noderange)
try:
handler = funmap[operation]
except KeyError:
argparser.print_help()
sys.exit(1)
handler(noderange, media)
if __name__ == '__main__':
main()
+37 -7
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/python2
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2015-2017 Lenovo
@@ -17,8 +17,13 @@
import optparse
import os
import signal
import sys
try:
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
except AttributeError:
pass
path = os.path.dirname(os.path.realpath(__file__))
path = os.path.realpath(os.path.join(path, '..', 'lib', 'python'))
if path.startswith('/opt'):
@@ -29,22 +34,47 @@ import confluent.client as client
argparser = optparse.OptionParser(
usage="Usage: %prog [options] noderange "
"([status|on|off|shutdown|boot|reset])")
argparser.add_option('-p', '--showprevious', dest='previous',
action='store_true', default=False,
help='Show previous power state')
argparser.add_option('-m', '--maxnodes', type='int',
help='Specify a maximum number of '
'nodes to change power state, '
'prompting if over the threshold')
(options, args) = argparser.parse_args()
try:
noderange = args[0]
except IndexError:
argparser.print_help()
sys.exit(1)
client.check_globbing(noderange)
setstate = None
if len(sys.argv) > 2:
if len(args) > 1:
if setstate == 'softoff':
setstate = 'shutdown'
elif not sys.argv[2] in ('stat', 'state', 'status'):
setstate = sys.argv[2]
elif not args[1] in ('stat', 'state', 'status'):
setstate = args[1]
if setstate not in (None, 'on', 'off', 'shutdown', 'boot', 'reset'):
argparser.print_help()
sys.exit(1)
session = client.Command()
exitcode = 0
session.add_precede_key('oldstate')
sys.exit(
session.simple_noderange_command(noderange, '/power/state', setstate))
if options.previous:
# get previous states
prev = {}
for rsp in session.read("/noderange/{0}/power/state".format(noderange)):
# gets previous (current) states
databynode = rsp["databynode"]
for node in databynode:
prev[node] = databynode[node]["state"]["value"]
# add dictionary to session
session.add_precede_dict(prev)
sys.exit(session.simple_noderange_command(noderange, '/power/state', setstate, promptover=options.maxnodes))
+57
View File
@@ -0,0 +1,57 @@
#!/usr/bin/python2
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2017 Lenovo
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import optparse
import os
import signal
import sys
try:
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
except AttributeError:
pass
path = os.path.dirname(os.path.realpath(__file__))
path = os.path.realpath(os.path.join(path, '..', 'lib', 'python'))
if path.startswith('/opt'):
sys.path.append(path)
import confluent.client as client
argparser = optparse.OptionParser(
usage='''\n %prog noderange
\n ''')
argparser.add_option('-m', '--maxnodes', type='int',
help='Specify a maximum number of '
'nodes to delete, '
'prompting if over the threshold')
(options, args) = argparser.parse_args()
if len(args) != 1:
argparser.print_help()
sys.exit(1)
noderange = args[0]
client.check_globbing(noderange)
session = client.Command()
exitcode = 0
session.stop_if_noderange_over(noderange, options.maxnodes)
for r in session.delete('/noderange/{0}'.format(noderange)):
if 'error' in r:
sys.stderr.write(r['error'] + '\n')
exitcode |= 1
if 'deleted' in r:
print('{0}: deleted'.format(r['deleted']))
sys.exit(exitcode)
+52
View File
@@ -0,0 +1,52 @@
#!/usr/bin/python2
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2019 Lenovo
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import optparse
import os
import signal
import sys
try:
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
except AttributeError:
pass
path = os.path.dirname(os.path.realpath(__file__))
path = os.path.realpath(os.path.join(path, '..', 'lib', 'python'))
if path.startswith('/opt'):
sys.path.append(path)
import confluent.client as client
argparser = optparse.OptionParser(usage="Usage: %prog <noderange> <newname>")
(options, args) = argparser.parse_args()
try:
noderange = args[0]
except IndexError:
argparser.print_help()
sys.exit(1)
client.check_globbing(noderange)
identifystate = None
if len(sys.argv) > 2:
newname = sys.argv[2]
else:
argparser.print_help()
sys.exit(1)
session = client.Command()
exitcode = 0
sys.exit(
session.simple_noderange_command(noderange, 'attributes/rename', newname))
+66
View File
@@ -0,0 +1,66 @@
#!/usr/bin/python2
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2015-2017 Lenovo
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import optparse
import os
import signal
import sys
try:
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
except AttributeError:
pass
path = os.path.dirname(os.path.realpath(__file__))
path = os.path.realpath(os.path.join(path, '..', 'lib', 'python'))
if path.startswith('/opt'):
sys.path.append(path)
import confluent.client as client
argparser = optparse.OptionParser(usage="Usage: %prog <noderange>")
argparser.add_option('-m', '--maxnodes', type='int',
help='Specify a maximum number of '
'nodes to reseat, '
'prompting if over the threshold')
(options, args) = argparser.parse_args()
try:
noderange = args[0]
except IndexError:
argparser.print_help()
sys.exit(1)
client.check_globbing(noderange)
session = client.Command()
exitcode = 0
errorNodes = set([])
session.stop_if_noderange_over(noderange, options.maxnodes)
success = session.simple_noderange_command(noderange, 'power/reseat', 'reseat', key='reseat', errnodes=errorNodes) # = 0 if successful
# Determine which nodes were successful and print them
allNodes = set([])
for node in session.read('/noderange/{0}/nodes/'.format(noderange)):
allNodes.add(node['item']['href'].replace("/", ""))
goodNodes = allNodes - errorNodes
for node in goodNodes:
print(node + ": Reseat successful")
sys.exit(success)
+159
View File
@@ -0,0 +1,159 @@
#!/usr/bin/python2
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2016-2017 Lenovo
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from collections import deque
import optparse
import os
import select
import shlex
import signal
import subprocess
import sys
try:
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
except AttributeError:
pass
path = os.path.dirname(os.path.realpath(__file__))
path = os.path.realpath(os.path.join(path, '..', 'lib', 'python'))
if path.startswith('/opt'):
sys.path.append(path)
import confluent.client as client
import confluent.screensqueeze as sq
import confluent.sortutil as sortutil
def run():
argparser = optparse.OptionParser(
usage="Usage: %prog location noderange:location",
)
argparser.add_option('-m', '--maxnodes', type='int',
help='Specify a maximum number of '
'nodes to run rsync to, '
'prompting if over the threshold')
argparser.add_option('-f', '-c', '--count', type='int', default=168,
help='Number of nodes to concurrently rsync')
# among other things, FD_SETSIZE limits. Besides, spawning too many
# processes can be unkind for the unaware on memory pressure and such...
argparser.disable_interspersed_args()
(options, args) = argparser.parse_args()
if len(args) < 2 or ':' not in args[-1]:
argparser.print_help()
sys.exit(1)
concurrentprocs = options.count
noderange, targpath = args[-1].split(':', 1)
client.check_globbing(noderange)
c = client.Command()
cmdstr = ' '.join(args[:-1])
cmdstr = 'rsync -av --info=progress2 ' + cmdstr
cmdstr += ' {node}:' + targpath
currprocs = 0
all = set([])
pipedesc = {}
pendingexecs = deque()
exitcode = 0
c.stop_if_noderange_over(noderange, options.maxnodes)
for exp in c.create('/noderange/{0}/attributes/expression'.format(noderange),
{'expression': cmdstr}):
if 'error' in exp:
sys.stderr.write(exp['error'] + '\n')
exitcode |= exp.get('errorcode', 1)
ex = exp.get('databynode', ())
for node in ex:
cmd = ex[node]['value']
if not isinstance(cmd, bytes) and not isinstance(cmd, str):
cmd = cmd.encode('utf-8')
cmdv = shlex.split(cmd)
if currprocs < concurrentprocs:
currprocs += 1
run_cmdv(node, cmdv, all, pipedesc)
else:
pendingexecs.append((node, cmdv))
if not all or exitcode:
sys.exit(exitcode)
rdy, _, _ = select.select(all, [], [], 10)
nodeerrs = {}
pernodeout = {}
pernodefile = {}
output = sq.ScreenPrinter(noderange, c)
while all:
for r in rdy:
desc = pipedesc[r]
node = desc['node']
data = True
while data and select.select([r], [], [], 0)[0]:
data = r.read(1)
if data:
if desc['type'] == 'stdout':
if node not in pernodeout:
pernodeout[node] = ''
pernodeout[node] += client.stringify(data)
if '\n' in pernodeout[node]:
currout, pernodeout[node] = pernodeout[node].split('\n', 1)
if currout:
pernodefile[node] = os.path.basename(currout)
if '\r' in pernodeout[node]:
currout, pernodeout[node] = pernodeout[node].split('\r', 1)
if currout:
currout = currout.split()
try:
currout = currout[1]
output.set_output(node, '{0}:{1}'.format(pernodefile[node], currout))
except IndexError:
pernodefile = currout[0]
pass
else:
output.set_output(node, 'error!')
if node not in nodeerrs:
nodeerrs[node] = ''
nodeerrs[node] += client.stringify(data)
else:
pop = desc['popen']
ret = pop.poll()
if ret is not None:
exitcode = exitcode | ret
all.discard(r)
r.close()
if node not in nodeerrs:
output.set_output(node, 'complete')
if desc['type'] == 'stdout' and pendingexecs:
node, cmdv = pendingexecs.popleft()
run_cmdv(node, cmdv, all, pipedesc)
if all:
rdy, _, _ = select.select(all, [], [], 10)
for node in nodeerrs:
for line in nodeerrs[node].split('\n'):
sys.stderr.write('{0}: {1}\n'.format(node, line))
sys.exit(exitcode)
def run_cmdv(node, cmdv, all, pipedesc):
nopen = subprocess.Popen(
cmdv, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
pipedesc[nopen.stdout] = {'node': node, 'popen': nopen,
'type': 'stdout'}
pipedesc[nopen.stderr] = {'node': node, 'popen': nopen,
'type': 'stderr'}
all.add(nopen.stdout)
all.add(nopen.stderr)
if __name__ == '__main__':
run()
+112 -53
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/python2
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2016-2017 Lenovo
@@ -15,72 +15,131 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from collections import deque
import optparse
import os
import select
import shlex
import signal
import subprocess
import sys
try:
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
except AttributeError:
pass
path = os.path.dirname(os.path.realpath(__file__))
path = os.path.realpath(os.path.join(path, '..', 'lib', 'python'))
if path.startswith('/opt'):
sys.path.append(path)
import confluent.client as client
import confluent.sortutil as sortutil
argparser = optparse.OptionParser(
usage="Usage: %prog node commandexpression",
epilog="Expressions are the same as in attributes, e.g. "
"'ipmitool -H {hardwaremanagement.manager}' will be expanded.")
argparser.disable_interspersed_args()
(options, args) = argparser.parse_args()
if len(args) < 2:
argparser.print_help()
sys.exit(1)
c = client.Command()
cmdstr = " ".join(args[1:])
def run():
argparser = optparse.OptionParser(
usage="Usage: %prog [options] noderange commandexpression",
epilog="Expressions are the same as in attributes, e.g. "
"'ipmitool -H {hardwaremanagement.manager}' will be expanded.")
argparser.add_option('-f', '-c', '--count', type='int', default=168,
help='Number of commands to run at a time')
argparser.add_option('-n', '--nonodeprefix', action='store_true',
help='Do not prefix output with node names')
argparser.add_option('-m', '--maxnodes', type='int',
help='Specify a maximum number of '
'nodes to run the command with, '
'prompting if over the threshold')
# among other things, FD_SETSIZE limits. Besides, spawning too many
# processes can be unkind for the unaware on memory pressure and such...
argparser.disable_interspersed_args()
(options, args) = argparser.parse_args()
if len(args) < 2:
argparser.print_help()
sys.exit(1)
concurrentprocs = options.count
client.check_globbing(args[0])
c = client.Command()
cmdstr = " ".join(args[1:])
nodeforpopen = {}
popens = []
for exp in c.create('/noderange/{0}/attributes/expression'.format(args[0]),
{'expression': cmdstr}):
ex = exp['databynode']
for node in ex:
cmd = ex[node]['value'].encode('utf-8')
cmdv = shlex.split(cmd)
nopen = subprocess.Popen(
cmdv, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
popens.append(nopen)
nodeforpopen[nopen] = node
all = set([])
pipedesc = {}
exitcode = 0
for pop in popens:
node = nodeforpopen[pop]
pipedesc[pop.stdout] = { 'node': node, 'popen': pop, 'type': 'stdout'}
pipedesc[pop.stderr] = {'node': node, 'popen': pop, 'type': 'stderr'}
all.add(pop.stdout)
all.add(pop.stderr)
rdy, _, _ = select.select(all, [], [], 10)
while all and rdy:
for r in rdy:
data = r.readline()
desc = pipedesc[r]
if data:
node = desc['node']
if desc['type'] == 'stdout':
sys.stdout.write('{0}: {1}'.format(node,data))
currprocs = 0
all = set([])
pipedesc = {}
pendingexecs = deque()
exitcode = 0
c.stop_if_noderange_over(args[0], options.maxnodes)
for exp in c.create('/noderange/{0}/attributes/expression'.format(args[0]),
{'expression': cmdstr}):
if 'error' in exp:
sys.stderr.write(exp['error'] + '\n')
exitcode |= exp.get('errorcode', 1)
ex = exp.get('databynode', ())
for node in ex:
cmd = ex[node]['value']
if not isinstance(cmd, bytes) and not isinstance(cmd, str):
cmd = cmd.encode('utf-8')
cmdv = shlex.split(cmd)
if currprocs < concurrentprocs:
currprocs += 1
run_cmdv(node, cmdv, all, pipedesc)
else:
sys.stderr.write('{0}: {1}'.format(node, data))
else:
pop = desc['popen']
ret = pop.poll()
if ret is not None:
exitcode = exitcode | ret
all.discard(r)
if all:
rdy, _, _ = select.select(all, [], [], 10)
sys.exit(exitcode)
pendingexecs.append((node, cmdv))
if not all or exitcode:
sys.exit(exitcode)
rdy, _, _ = select.select(all, [], [], 10)
while all:
pernodeout = {}
for r in rdy:
desc = pipedesc[r]
node = desc['node']
data = True
while data and select.select([r], [], [], 0)[0]:
data = r.readline()
if data:
if desc['type'] == 'stdout':
if node not in pernodeout:
pernodeout[node] = []
pernodeout[node].append(data)
else:
data = client.stringify(data)
if options.nonodeprefix:
sys.stderr.write(data)
else:
sys.stderr.write('{0}: {1}'.format(node, data))
sys.stderr.flush()
else:
pop = desc['popen']
ret = pop.poll()
if ret is not None:
exitcode = exitcode | ret
all.discard(r)
r.close()
if desc['type'] == 'stdout' and pendingexecs:
node, cmdv = pendingexecs.popleft()
run_cmdv(node, cmdv, all, pipedesc)
for node in sortutil.natural_sort(pernodeout):
for line in pernodeout[node]:
line = client.stringify(line)
if options.nonodeprefix:
sys.stdout.write(line)
else:
sys.stdout.write('{0}: {1}'.format(node, line))
sys.stdout.flush()
if all:
rdy, _, _ = select.select(all, [], [], 10)
sys.exit(exitcode)
def run_cmdv(node, cmdv, all, pipedesc):
nopen = subprocess.Popen(
cmdv, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
pipedesc[nopen.stdout] = {'node': node, 'popen': nopen,
'type': 'stdout'}
pipedesc[nopen.stderr] = {'node': node, 'popen': nopen,
'type': 'stderr'}
all.add(nopen.stdout)
all.add(nopen.stderr)
if __name__ == '__main__':
run()
+29 -10
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/python2
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2015-2017 Lenovo
@@ -19,9 +19,14 @@ import csv
import datetime
import optparse
import os
import signal
import sys
import time
try:
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
except AttributeError:
pass
path = os.path.dirname(os.path.realpath(__file__))
path = os.path.realpath(os.path.join(path, '..', 'lib', 'python'))
if path.startswith('/opt'):
@@ -31,6 +36,7 @@ import confluent.client as client
sensorcollections = {
'all': 'sensors/hardware/all/all',
'energy': 'sensors/hardware/energy/all',
'temperature': 'sensors/hardware/temperature/all',
'temp': 'sensors/hardware/temperature/all',
'power': 'sensors/hardware/power/all',
@@ -59,6 +65,7 @@ if options.numreadings:
options.interval = 1
try:
noderange = args[0]
client.check_globbing(noderange)
except IndexError:
argparser.print_help()
sys.exit(1)
@@ -73,7 +80,6 @@ for sensorgroup in args[1:]:
sensors.append('sensors/hardware/all/' + sensor)
if not sensors:
sensors = ['sensors/hardware/all/all']
session = client.Command()
exitcode = 0
sensorheaders = {}
@@ -108,7 +114,8 @@ def sensorpass(showout=True, appendtime=False):
continue
for redundant_state in ('Non-Critical', 'Critical'):
try:
sensedata['states'].remove(redundant_state)
if sensedata.get('states', False):
sensedata['states'].remove(redundant_state)
except ValueError:
pass
resultdata[node][sensedata['name']] = sensedata
@@ -120,15 +127,18 @@ def sensorpass(showout=True, appendtime=False):
if showout:
if sensedata['value'] is None:
showval = ''
elif isinstance(sensedata['value'], float):
showval = u' {0:.5f} '.format(sensedata['value'])
else:
showval = u' {0} '.format(sensedata['value'])
if sensedata['units'] not in (None, u''):
showval += sensedata['units']
if sensedata['health'] != 'ok':
if sensedata.get('health', 'ok') != 'ok':
datadescription = [sensedata['health']]
else:
datadescription = []
datadescription.extend(sensedata['states'])
if sensedata.get('states', False):
datadescription.extend(sensedata['states'])
if datadescription:
if showval == '':
showval += u' {0}'.format(
@@ -139,15 +149,19 @@ def sensorpass(showout=True, appendtime=False):
if appendtime:
showval += ' @' + time.strftime(
'%Y-%m-%dT%H:%M:%S')
print(u'{0}: {1}:{2}'.format(
node, sensedata['name'], showval).encode('utf-8'))
printval = u'{0}: {1}:{2}'.format(
node, sensedata['name'], showval)
if not isinstance(printval, str):
printval = printval.encode('utf-8')
print(printval)
sys.stdout.flush()
return resultdata
def format_csv(csvwriter, orderedsensors, resdata, showtime=True):
for nodekey in resdata:
if showtime:
if showtime.is_integer():
if isinstance(showtime, int):
rowdata = [time.strftime('%Y-%m-%dT%H:%M:%S'), nodekey]
else:
rowdata = [time.strftime('%Y-%m-%dT%H:%M:%S.') +
@@ -174,6 +188,7 @@ def format_csv(csvwriter, orderedsensors, resdata, showtime=True):
except KeyError:
rowdata.append('N/A')
csvwriter.writerow(rowdata)
sys.stdout.flush()
def main():
@@ -187,7 +202,11 @@ def main():
orderedsensors.append(name)
orderedsensors.sort()
for name in orderedsensors:
headernames.append(sensorheaders[name].encode('utf-8'))
headername = sensorheaders[name]
if (not isinstance(headername, str) and
not isinstance(headername, bytes)):
headername = headername.encode('utf-8')
headernames.append(headername)
if options.csv:
linebyline = False
csvwriter = csv.writer(sys.stdout)
@@ -211,7 +230,7 @@ def main():
sys.exit(exitcode)
sleeptime = nextstart - os.times()[4]
if sleeptime > 0:
time.sleep(nextstart - os.times()[4])
time.sleep(sleeptime)
else:
if options.csv:
format_csv(csvwriter, orderedsensors, resdata, showtime=False)
+15 -5
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/python2
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2015 Lenovo
@@ -17,8 +17,13 @@
import optparse
import os
import signal
import sys
try:
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
except AttributeError:
pass
path = os.path.dirname(os.path.realpath(__file__))
path = os.path.realpath(os.path.join(path, '..', 'lib', 'python'))
if path.startswith('/opt'):
@@ -38,17 +43,21 @@ argparser.add_option('-p', '--persist', dest='persist', action='store_true',
argparser.add_option('-u', '--uefi', dest='uefi', action='store_true',
default=True,
help='Request UEFI style boot (rather than BIOS)')
argparser.add_option('-m', '--maxnodes', type='int',
help='Specify a maximum number of '
'nodes to modify next boot device, '
'prompting if over the threshold')
(options, args) = argparser.parse_args()
try:
noderange = args[0]
client.check_globbing(noderange)
except IndexError:
argparser.print_help()
sys.exit(1)
bootdev = None
if len(sys.argv) > 2:
bootdev = sys.argv[2]
if len(args) > 1:
bootdev = args[1]
if bootdev in ('net', 'pxe'):
bootdev = 'network'
session = client.Command()
@@ -57,6 +66,7 @@ if options.biosmode:
bootmode = 'bios'
else:
bootmode = 'uefi'
session.stop_if_noderange_over(noderange, options.maxnodes)
sys.exit(session.simple_noderange_command(noderange, '/boot/nextdevice', bootdev,
bootmode=bootmode,
persistent=options.persist))
persistent=options.persist))
+113 -53
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/python2
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2016-2017 Lenovo
@@ -15,72 +15,132 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from collections import deque
import optparse
import os
import select
import shlex
import signal
import subprocess
import sys
try:
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
except AttributeError:
pass
path = os.path.dirname(os.path.realpath(__file__))
path = os.path.realpath(os.path.join(path, '..', 'lib', 'python'))
if path.startswith('/opt'):
sys.path.append(path)
import confluent.client as client
import confluent.sortutil as sortutil
argparser = optparse.OptionParser(
usage="Usage: %prog node commandexpression",
epilog="Expressions are the same as in attributes, e.g. "
"'ipmitool -H {hardwaremanagement.manager}' will be expanded.")
argparser.disable_interspersed_args()
(options, args) = argparser.parse_args()
if len(args) < 2:
argparser.print_help()
sys.exit(1)
c = client.Command()
cmdstr = " ".join(args[1:])
def run():
nodeforpopen = {}
popens = []
for exp in c.create('/noderange/{0}/attributes/expression'.format(args[0]),
{'expression': cmdstr}):
ex = exp['databynode']
for node in ex:
cmd = ex[node]['value'].encode('utf-8')
cmdv = ['ssh', node] + shlex.split(cmd)
nopen = subprocess.Popen(
cmdv, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
popens.append(nopen)
nodeforpopen[nopen] = node
argparser = optparse.OptionParser(
usage="Usage: %prog [options] noderange commandexpression",
epilog="Expressions are the same as in attributes, e.g. "
"'ipmitool -H {hardwaremanagement.manager}' will be expanded.")
argparser.add_option('-f', '-c', '--count', type='int', default=168,
help='Number of commands to run at a time')
argparser.add_option('-n', '--nonodeprefix', action='store_true',
help='Do not prefix output with node names')
argparser.add_option('-m', '--maxnodes', type='int',
help='Specify a maximum number of '
'nodes to run remote ssh command to, '
'prompting if over the threshold')
# among other things, FD_SETSIZE limits. Besides, spawning too many
# processes can be unkind for the unaware on memory pressure and such...
argparser.disable_interspersed_args()
(options, args) = argparser.parse_args()
if len(args) < 2:
argparser.print_help()
sys.exit(1)
client.check_globbing(args[0])
concurrentprocs = options.count
c = client.Command()
cmdstr = " ".join(args[1:])
all = set([])
pipedesc = {}
exitcode = 0
for pop in popens:
node = nodeforpopen[pop]
pipedesc[pop.stdout] = { 'node': node, 'popen': pop, 'type': 'stdout'}
pipedesc[pop.stderr] = {'node': node, 'popen': pop, 'type': 'stderr'}
all.add(pop.stdout)
all.add(pop.stderr)
rdy, _, _ = select.select(all, [], [], 10)
while all and rdy:
for r in rdy:
data = r.readline()
desc = pipedesc[r]
if data:
node = desc['node']
if desc['type'] == 'stdout':
sys.stdout.write('{0}: {1}'.format(node,data))
currprocs = 0
all = set([])
pipedesc = {}
pendingexecs = deque()
exitcode = 0
c.stop_if_noderange_over(args[0], options.maxnodes)
for exp in c.create('/noderange/{0}/attributes/expression'.format(args[0]),
{'expression': cmdstr}):
if 'error' in exp:
sys.stderr.write(exp['error'] + '\n')
exitcode |= exp.get('errorcode', 1)
ex = exp.get('databynode', ())
for node in ex:
cmd = ex[node]['value']
if not isinstance(cmd, str) and not isinstance(cmd, bytes):
cmd = cmd.encode('utf-8')
cmdv = ['ssh', node, cmd]
if currprocs < concurrentprocs:
currprocs += 1
run_cmdv(node, cmdv, all, pipedesc)
else:
sys.stderr.write('{0}: {1}'.format(node, data))
else:
pop = desc['popen']
ret = pop.poll()
if ret is not None:
exitcode = exitcode | ret
all.discard(r)
if all:
rdy, _, _ = select.select(all, [], [], 10)
sys.exit(exitcode)
pendingexecs.append((node, cmdv))
if not all or exitcode:
sys.exit(exitcode)
rdy, _, _ = select.select(all, [], [], 10)
while all:
pernodeout = {}
for r in rdy:
desc = pipedesc[r]
node = desc['node']
data = True
while data and select.select([r], [], [], 0)[0]:
data = r.readline()
if data:
if desc['type'] == 'stdout':
if node not in pernodeout:
pernodeout[node] = []
pernodeout[node].append(data)
else:
data = client.stringify(data)
if options.nonodeprefix:
sys.stderr.write(data)
else:
sys.stderr.write('{0}: {1}'.format(node, data))
sys.stderr.flush()
else:
pop = desc['popen']
ret = pop.poll()
if ret is not None:
exitcode = exitcode | ret
all.discard(r)
r.close()
if desc['type'] == 'stdout' and pendingexecs:
node, cmdv = pendingexecs.popleft()
run_cmdv(node, cmdv, all, pipedesc)
for node in sortutil.natural_sort(pernodeout):
for line in pernodeout[node]:
line = client.stringify(line)
if options.nonodeprefix:
sys.stdout.write(line)
else:
sys.stdout.write('{0}: {1}'.format(node, line))
sys.stdout.flush()
if all:
rdy, _, _ = select.select(all, [], [], 10)
sys.exit(exitcode)
def run_cmdv(node, cmdv, all, pipedesc):
nopen = subprocess.Popen(
cmdv, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
pipedesc[nopen.stdout] = {'node': node, 'popen': nopen,
'type': 'stdout'}
pipedesc[nopen.stderr] = {'node': node, 'popen': nopen,
'type': 'stderr'}
all.add(nopen.stdout)
all.add(nopen.stderr)
if __name__ == '__main__':
run()
+237
View File
@@ -0,0 +1,237 @@
#!/usr/bin/python2
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2018 Lenovo
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import optparse
import os
import signal
import sys
try:
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
except AttributeError:
pass
path = os.path.dirname(os.path.realpath(__file__))
path = os.path.realpath(os.path.join(path, '..', 'lib', 'python'))
if path.startswith('/opt'):
sys.path.append(path)
import confluent.client as client
exitcode = 0
class OptParser(optparse.OptionParser):
def format_epilog(self, formatter):
return self.expand_prog_name(self.epilog)
def mbtohuman(mb):
if mb > 1000000:
return '{0:.3f} TB'.format(mb/1000000.0)
if mb > 1000:
return '{0:.3f} GB'.format(mb/1000.0)
return '{0:.3f} MB'.format(mb)
def showstorage(noderange, options, args):
global exitcode
session = client.Command()
disks = {}
arrays = {}
volumes = {}
scfg = session.read('/noderange/{0}/configuration/storage/all'.format(
noderange))
_print_cfg(scfg)
def _print_cfg(scfg):
global exitcode
storagebynode = {}
for e in scfg:
if 'error' in e:
sys.stderr.write(e['error'] + '\n')
exitcode = e.get('errorcode', 1)
for node in e.get('databynode', {}):
curr = e['databynode'][node]
if 'error' in curr:
if 'no available drives' in curr['error']:
curr['error'] += ' (drives must be in unconfigured state to be available, they must not be in jbod or online state)'
sys.stderr.write('{0}: {1}\n'.format(node, curr['error']))
exitcode = curr.get('errorcode', 1)
continue
if node not in storagebynode:
storagebynode[node] = {'disks': [], 'arrays': [],
'volumes': []}
storagebynode[node][curr['type'] + 's'].append(curr)
for node in storagebynode:
for disk in sorted(storagebynode[node]['disks'],
key=lambda x: x['name']):
print('{0}: Disk {1} Description: {2}'.format(
node, disk['name'], disk['description']))
print('{0}: Disk {1} State: {2}'.format(node, disk['name'],
disk['state']))
print('{0}: Disk {1} FRU: {2}'.format(node, disk['name'],
disk['fru']))
print('{0}: Disk {1} Serial Number: {2}'.format(node, disk['name'],
disk['serial']))
if disk['array']:
print('{0}: Disk {1} Array: {2}'.format(node, disk['name'],
disk['array']))
for arr in storagebynode[node]['arrays']:
print('{0}: Array {1} Available Capacity: {2}'.format(
node, arr['id'], mbtohuman(arr['available'])))
print('{0}: Array {1} Total Capacity: {2}'.format(
node, arr['id'], mbtohuman(arr['capacity'])))
print('{0}: Array {1} RAID: {2}'.format(node, arr['id'],
arr['raid']))
print('{0}: Array {1} Disks: {2}'.format(node, arr['id'], ','.join(
arr['disks'])))
print(
'{0}: Array {1} Volumes: {2}'.format(node, arr['id'], ','.join(
arr['volumes'])))
for vol in storagebynode[node]['volumes']:
print('{0}: Volume {1}: Size: {2}'.format(node, vol['name'],
mbtohuman(vol['size'])))
print('{0}: Volume {1}: State: {2}'.format(node, vol['name'],
vol['state']))
print('{0}: Volume {1}: Array {2}'.format(node, vol['name'],
vol['array']))
def createstorage(noderange, options, args):
if options.raidlevel is None or options.disks is None:
sys.stderr.write('-r and -d are required arguments to create array\n')
sys.exit(1)
session = client.Command()
session.stop_if_noderange_over(noderange, options.maxnodes)
names = options.name
if names is None:
names = ''.join(args)
parms = {'disks': options.disks, 'raidlevel': options.raidlevel,
'name': names}
if options.size:
parms['size'] = options.size
if options.stripsizes:
parms['stripsizes'] = options.stripsizes
_print_cfg(session.create(
'/noderange/{0}/configuration/storage/volumes/{1}'.format(
noderange, names), parms))
def deletestorage(noderange, options, args):
if options.name is None:
if len(args) == 1:
names = args[0]
else:
sys.stderr.write('-n is required to indicate volume(s) to delete\n')
sys.exit(1)
else:
names = options.name
session = client.Command()
session.stop_if_noderange_over(noderange, options.maxnodes)
for rsp in session.delete(
'/noderange/{0}/configuration/storage/volumes/{1}'.format(
noderange, names)):
if 'deleted' in rsp:
print('Deleted: {0}'.format(rsp['deleted']))
elif 'databynode' in rsp:
for node in rsp['databynode']:
if 'error' in rsp['databynode'][node]:
sys.stderr.write('{0}: {1}\n'.format(
node, rsp['databynode'][node]['error']))
else:
sys.stderr.write('{0}: {1}\n'.format(
node, repr(rsp['databynode'][node])))
else:
print(repr(rsp))
def setdisk(noderange, options, args):
if options.disks is None:
if len(args):
names = args.pop(0)
else:
sys.stderr.write('-d is required to indicate disk to modify\n')
sys.exit(1)
else:
names = options.disks
if not len(args) or args[0] not in ('hotspare', 'jbod', 'unconfigured'):
sys.stderr.write('diskset requires valid state as argument (hotspare, jbod, unconfigured)\n')
sys.exit(1)
session = client.Command()
session.stop_if_noderange_over(noderange, options.maxnodes)
scfg = session.update('/noderange/{0}/configuration/storage/disks/{1}'.format(noderange, names), {'state': args[0]})
_print_cfg(scfg)
funmap = {
'create': createstorage,
'show': showstorage,
'diskset': setdisk,
'delete': deletestorage,
'rm': deletestorage,
}
def main():
argparser = OptParser(
usage='Usage: %prog <noderange> [show|create|delete|diskset]',
epilog='',
)
argparser.add_option('-r', '--raidlevel', type='int',
help='RAID level to use when creating an array')
argparser.add_option('-d', '--disks', type='str',
help='Comma separated list of disks to use, or the '
'word "rest" to indicate use of all available '
'disks')
argparser.add_option('-s', '--size', type='str',
help='Comma separated list of sizes to use when '
'creating volumes. The sizes may be absolute '
'size (e.g. 16gb), percentage (10%) or the word '
'"rest" to use remaining capacity, default '
'behavior is to use all capacity to make a '
'volume')
argparser.add_option('-n', '--name', type='str',
help='Comma separated list of names to use when '
'naming volumes, or selecting a volume for '
'delete. Default behavior is to use '
'implementation provided default names.')
argparser.add_option('-z', '--stripsizes', type='str',
help='Comma separated list of stripsizes to use when creating volumes. '
'This value is in kilobytes. The default behavior is to allow the '
'storage controller to decide.')
argparser.add_option('-m', '--maxnodes', type='int',
help='Specify a maximum number of '
'nodes to configure storage on, '
'prompting if over the threshold')
(options, args) = argparser.parse_args()
if len(args) == 1:
args.append('show')
try:
noderange = args[0]
operation = args[1]
except IndexError:
argparser.print_help()
sys.exit(1)
client.check_globbing(noderange)
try:
handler = funmap[operation]
except KeyError:
argparser.print_help()
sys.exit(1)
handler(noderange, options, args[2:])
if __name__ == '__main__':
main()
+152
View File
@@ -0,0 +1,152 @@
#!/usr/bin/python2
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2018 Lenovo
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import optparse
import os
import signal
import sys
import time
try:
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
except AttributeError:
pass
path = os.path.dirname(os.path.realpath(__file__))
path = os.path.realpath(os.path.join(path, '..', 'lib', 'python'))
if path.startswith('/opt'):
sys.path.append(path)
import confluent.client as client
import confluent.screensqueeze as sq
exitcode = 0
def get_update_progress(session, url):
for res in session.read(url):
status = res['phase']
percent = res['progress']
detail = res['detail']
if status == 'error':
text = 'error!'
else:
text = '{0}: {1:3.0f}%'.format(status, percent)
return text, status, detail
def printerror(res, node=None):
global exitcode
if 'errorcode' in res:
exitcode = res['errorcode']
if 'error' in res:
if node:
sys.stderr.write('{0}: {1}\n'.format(node, res['error']))
else:
sys.stderr.write('{0}\n'.format(res['error']))
if 'errorcode' not in res:
exitcode = 1
for node in res.get('databynode', ()):
printerror(res['databynode'][node], node)
def download_servicedata(noderange, media, options):
global exitcode
session = client.Command()
output = sq.ScreenPrinter(noderange, session)
filename = os.path.abspath(media)
resource = '/noderange/{0}/support/servicedata/'.format(noderange)
upargs = {'filename': filename}
noderrs = {}
nodeurls = {}
session.stop_if_noderange_over(noderange, options.maxnodes)
for res in session.create(resource, upargs):
if 'created' not in res:
for nodename in res.get('databynode', ()):
output.set_output(nodename, 'error!')
noderrs[nodename] = res['databynode'][nodename].get(
'error', 'Unknown Error')
continue
watchurl = res['created']
currnode = watchurl.split('/')[1]
nodeurls[currnode] = '/' + watchurl
while nodeurls:
for node in list(nodeurls):
progress, status, err = get_update_progress(
session, nodeurls[node])
if status == 'error':
exitcode = 1
noderrs[node] = err
if status in ('error', 'complete', 'pending'):
list(session.delete(nodeurls[node]))
del nodeurls[node]
output.set_output(node, progress)
time.sleep(2)
allerrnodes = ','.join(noderrs)
if noderrs:
sys.stderr.write(
'Nodes had errors retrieving service data ({0})!\n'.format(allerrnodes))
for node in noderrs:
sys.stderr.write('{0}: {1}\n'.format(node, noderrs[node]))
funmap = {
'servicedata': download_servicedata,
}
class OptParser(optparse.OptionParser):
def format_epilog(self, formatter):
return self.expand_prog_name(self.epilog)
def main():
argparser = OptParser(
usage="Usage: %prog <noderange> servicedata "
"<filename>",
epilog='\nservicedata will save service data to the given '
'directory. It is saved to the location on the relevant '
'management server (the confluent server if running remote, '
'and the collective.manager if in collective)\n'
'\n\nSee `man %prog` for more info.\n')
argparser.add_option('-m', '--maxnodes', type='int',
help='Specify a maximum number of '
'nodes to download diagnostic data from, '
'prompting if over the threshold')
(options, args) = argparser.parse_args()
media = None
try:
noderange = args[0]
operation = args[1]
arglength = 2
if operation == 'servicedata':
media = args[2]
arglength = 3
if len(args) > arglength:
argparser.print_help()
sys.exit(1)
except IndexError:
argparser.print_help()
sys.exit(1)
client.check_globbing(noderange)
try:
handler = funmap[operation]
except KeyError:
argparser.print_help()
sys.exit(1)
handler(noderange, media, options)
if __name__ == '__main__':
main()
+167
View File
@@ -0,0 +1,167 @@
#!/usr/bin/python2
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2019 Lenovo
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import argparse
import csv
import fcntl
import io
import numpy as np
import os
import sixel
import subprocess
import sys
class DumbWriter(sixel.SixelWriter):
def restore_position(self, output):
return
def plot(gui, output, plotdata, bins):
import matplotlib as mpl
if not gui:
mpl.use('Agg')
import matplotlib.pyplot as plt
n, bins, patches = plt.hist(plotdata, bins)
plt.show()
if not gui:
if output:
tdata = output
else:
tdata = io.BytesIO()
plt.savefig(tdata)
if not gui and not output:
writer = DumbWriter()
writer.draw(tdata)
return n, bins
def textplot(plotdata, bins):
n, bins = np.histogram(plotdata, bins)
labels = []
for bin in bins:
labels.append('{0:0.1f}'.format(bin))
width = 80
# Since this will be primarily piped into, hard to get
# terminal width
labelwidth = 0
for lab in labels:
if len(lab) > labelwidth:
labelwidth = len(lab)
width -= (labelwidth) + 1
labelfmt = '{{0:>{0}s}}|'.format(labelwidth)
maxn = 0.0
for lgth in n:
if lgth > maxn:
maxn = float(lgth)
for i in range(len(n)):
print(labelfmt.format(labels[i]) + '=' * int(np.round((n[i]/maxn) * width)))
return n, bins
histogram = False
aparser = argparse.ArgumentParser(description='Quick access to common statistics')
aparser.add_argument('-c', type=int, default=0, help='Column number to analyze (default is last column)')
aparser.add_argument('-d', default=None, help='Value used to separate columns')
aparser.add_argument('-x', default=False, action='store_true', help='Output histogram in sixel format')
aparser.add_argument('-s', default=0, help='Number of header lines to skip before processing')
aparser.add_argument('-g', default=False, action='store_true', help='Open histogram in separate graphical window')
aparser.add_argument('-o', default=None, help='Output histogram to the specified filename in PNG format')
aparser.add_argument('-t', default=False, action='store_true', help='Output a histogram in text format')
aparser.add_argument('-v', default=False, action='store_true', help='Attempt to list nodes relevant to each histogram bar (requires -s, -o, or -t)')
aparser.add_argument('-b', type=int, default=10, help='Number of bins to use in histogram (default is 10)')
args = aparser.parse_args(sys.argv[1:])
plotdata = []
headlines = int(args.s)
while headlines >= 0:
data = sys.stdin.readline()
headlines -= 1
if args.d:
delimiter = args.d
else:
if '\t' in data:
delimiter = '\t'
elif ' ' in data:
delimiter = ' '
elif ',' in data:
delimiter = ','
else:
delimiter = ' ' # handle single column
data = list(csv.reader([data], delimiter=delimiter))[0]
nodebydatum = {}
idx = args.c - 1
autoidx = False
while data:
node = None
if ':' in data[0]:
node, data[0] = data[0].split(':', 1)
else:
node = data[0]
if idx == -1 and not autoidx:
while not autoidx:
try:
datum = float(data[idx])
except ValueError:
idx -= 1
continue
except IndexError:
sys.stderr.write('Unable to identify a numerical column\n')
sys.exit(1)
autoidx = True
else:
datum = float(data[idx])
if node:
if datum in nodebydatum:
nodebydatum[datum].add(node)
else:
nodebydatum[datum] = set([node])
plotdata.append(datum)
data = sys.stdin.readline()
data = list(csv.reader([data], delimiter=delimiter))[0]
n = None
if args.g or args.o or args.x:
n, bins = plot(args.g, args.o, plotdata, bins=args.b)
if args.t:
n, bins = textplot(plotdata, bins=args.b)
print('Samples: {5} Min: {3} Median: {0} Mean: {1} Max: {4} StandardDeviation: {2} Sum: {6}'.format(np.median(plotdata), np.mean(plotdata), np.std(plotdata), np.min(plotdata), np.max(plotdata), len(plotdata), np.sum(plotdata)))
if args.v and n is not None and nodebydatum:
print('')
currbin = bins[0]
bins = bins[1:]
currbinmembers = []
for datum in sorted(nodebydatum):
if datum > bins[0]:
nextbin = None
endbin = bins[0]
while len(bins) and bins[0] < datum:
nextbin = bins[0]
bins = bins[1:]
if not nextbin:
nextbin = np.max(plotdata)
print('Entries between {0} and {1}'.format(currbin, endbin))
currbin = nextbin
print('-' * 80)
print(','.join(sorted(currbinmembers)))
print('')
print('')
currbinmembers = []
for node in nodebydatum[datum]:
currbinmembers.append(node)
if currbinmembers:
print('Entries between {0} and {1}'.format(currbin, np.max(plotdata)))
print('-' * 80)
print(','.join(sorted(currbinmembers)))
print('')
print('')
+1
View File
@@ -0,0 +1 @@
../confluent_server/builddeb
+334 -65
View File
@@ -1,7 +1,7 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2014 IBM Corporation
# Copyright 2015-2016 Lenovo
# Copyright 2015-2019 Lenovo
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,17 +15,116 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import anydbm as dbm
try:
import anydbm as dbm
except ImportError:
import dbm
import csv
import errno
import fnmatch
import hashlib
import os
import shlex
import socket
import ssl
import sys
import confluent.tlvdata as tlvdata
import confluent.sortutil as sortutil
SO_PASSCRED = 16
_attraliases = {
'bmc': 'hardwaremanagement.manager',
'bmcuser': 'secret.hardwaremanagementuser',
'bmcpass': 'secret.hardwaremanagementpassword',
}
try:
input = raw_input
except NameError:
pass
def stringify(instr):
# Normalize unicode and bytes to 'str', correcting for
# current python version
if isinstance(instr, bytes) and not isinstance(instr, str):
return instr.decode('utf-8')
elif not isinstance(instr, bytes) and not isinstance(instr, str):
return instr.encode('utf-8')
return instr
class Tabulator(object):
def __init__(self, headers):
self.headers = headers
self.rows = []
def add_row(self, row):
self.rows.append(row)
def get_table(self, order=None):
i = 0
fmtstr = ''
separator = []
for head in self.headers:
if order and order == head:
order = i
neededlen = len(head)
for row in self.rows:
if len(row[i]) > neededlen:
neededlen = len(row[i])
separator.append('-' * (neededlen + 1))
fmtstr += '{{{0}:>{1}}}|'.format(i, neededlen + 1)
i = i + 1
fmtstr = fmtstr[:-1]
yield fmtstr.format(*self.headers)
yield fmtstr.format(*separator)
if order is not None:
for row in sorted(
self.rows,
key=lambda x: sortutil.naturalize_string(x[order])):
yield fmtstr.format(*row)
else:
for row in self.rows:
yield fmtstr.format(*row)
def write_csv(self, output, order=None):
output = csv.writer(output)
output.writerow(self.headers)
i = 0
for head in self.headers:
if order and order == head:
order = i
i = i + 1
if order is not None:
for row in sorted(
self.rows,
key=lambda x: sortutil.naturalize_string(x[order])):
output.writerow(row)
else:
for row in self.rows:
output.writerow(row)
def printerror(res, node=None):
exitcode = 0
if 'errorcode' in res:
exitcode = res['errorcode']
if 'error' in res:
if node:
sys.stderr.write('{0}: {1}\n'.format(node, res['error']))
else:
sys.stderr.write('{0}\n'.format(res['error']))
if 'errorcode' not in res:
exitcode = 1
return exitcode
def cprint(txt):
try:
print(txt)
except UnicodeEncodeError:
print(txt.encode('utf8'))
sys.stdout.flush()
def _parseserver(string):
if ']:' in string:
@@ -43,8 +142,10 @@ def _parseserver(string):
class Command(object):
def __init__(self, server=None):
self._prevdict = None
self._prevkeyname = None
self.connection = None
self._currnoderange = None
if server is None:
if 'CONFLUENT_HOST' in os.environ:
self.serverloc = os.environ['CONFLUENT_HOST']
@@ -54,6 +155,8 @@ class Command(object):
self.serverloc = server
if os.path.isabs(self.serverloc) and os.path.exists(self.serverloc):
self._connect_unix()
elif self.serverloc == '/var/run/confluent/api.sock':
raise Exception('Confluent service is not available')
else:
self._connect_tls()
tlvdata.recv(self.connection)
@@ -77,8 +180,13 @@ class Command(object):
def add_precede_key(self, keyname):
self._prevkeyname = keyname
def handle_results(self, ikey, rc, res):
def add_precede_dict(self, dict):
self._prevdict = dict
def handle_results(self, ikey, rc, res, errnodes=None):
if 'error' in res:
if errnodes is not None:
errnodes.add(self._currnoderange)
sys.stderr.write('Error: {0}\n'.format(res['error']))
if 'errorcode' in res:
return res['errorcode']
@@ -89,6 +197,8 @@ class Command(object):
res = res['databynode']
for node in res:
if 'error' in res[node]:
if errnodes is not None:
errnodes.add(node)
sys.stderr.write('{0}: Error: {1}\n'.format(
node, res[node]['error']))
if 'errorcode' in res[node]:
@@ -103,15 +213,19 @@ class Command(object):
else:
val = repr(res[node][ikey])
if self._prevkeyname and self._prevkeyname in res[node]:
print('{0}: {2}->{1}'.format(
cprint('{0}: {2}->{1}'.format(
node, val, res[node][self._prevkeyname]['value']))
elif self._prevdict and node in self._prevdict:
cprint('{0}: {2}->{1}'.format(
node, val, self._prevdict[node]))
else:
print('{0}: {1}'.format(node, val))
cprint('{0}: {1}'.format(node, val))
return rc
def simple_noderange_command(self, noderange, resource, input=None,
key=None, **kwargs):
key=None, errnodes=None, promptover=None, **kwargs):
try:
self._currnoderange = noderange
rc = 0
if resource[0] == '/':
resource = resource[1:]
@@ -123,16 +237,45 @@ class Command(object):
if input is None:
for res in self.read('/noderange/{0}/{1}'.format(
noderange, resource)):
rc = self.handle_results(ikey, rc, res)
rc = self.handle_results(ikey, rc, res, errnodes)
else:
self.stop_if_noderange_over(noderange, promptover)
kwargs[ikey] = input
for res in self.update('/noderange/{0}/{1}'.format(
noderange, resource), kwargs):
rc = self.handle_results(ikey, rc, res)
rc = self.handle_results(ikey, rc, res, errnodes)
self._currnoderange = None
return rc
except KeyboardInterrupt:
print('')
cprint('')
return 0
def stop_if_noderange_over(self, noderange, maxnodes):
if maxnodes is None:
return
nsize = self.get_noderange_size(noderange)
if nsize > maxnodes:
if nsize == 1:
nodename = list(self.read(
'/noderange/{0}/nodes/'.format(noderange)))[0].get('item', {}).get('href', None)
nodename = nodename[:-1]
p = input('Command is about to affect node {0}, continue (y/n)? '.format(nodename))
else:
p = input('Command is about to affect {0} nodes, continue (y/n)? '.format(nsize))
if p.lower() != 'y':
sys.stderr.write('Aborting at user request\n')
sys.exit(1)
raise Exception("Aborting at user request")
def get_noderange_size(self, noderange):
numnodes = 0
for node in self.read('/noderange/{0}/nodes/'.format(noderange)):
if node.get('item', {}).get('href', None):
numnodes += 1
else:
raise Exception("Error trying to size noderange {0}".format(noderange))
return numnodes
def simple_nodegroups_command(self, noderange, resource, input=None, key=None, **kwargs):
try:
@@ -155,7 +298,7 @@ class Command(object):
rc = self.handle_results(ikey, rc, res)
return rc
except KeyboardInterrupt:
print('')
cprint('')
return 0
def read(self, path, parameters=None):
@@ -222,22 +365,22 @@ class Command(object):
certreqs = ssl.CERT_NONE
knownhosts = True
self.connection = ssl.wrap_socket(self.connection, ca_certs=cacert,
cert_reqs=certreqs,
ssl_version=ssl.PROTOCOL_TLSv1)
cert_reqs=certreqs)
if knownhosts:
certdata = self.connection.getpeercert(binary_form=True)
fingerprint = 'sha512$' + hashlib.sha512(certdata).hexdigest()
fingerprint = fingerprint.encode('utf-8')
hostid = '@'.join((port, server))
khf = dbm.open(os.path.join(clientcfgdir, "knownhosts"), 'c', 384)
if hostid in khf:
if fingerprint == khf[hostid]:
return
else:
replace = raw_input(
replace = input(
"MISMATCHED CERTIFICATE DATA, ACCEPT NEW? (y/n):")
if replace not in ('y', 'Y'):
raise Exception("BAD CERTIFICATE")
print 'Adding new key for %s:%s' % (server, port)
cprint('Adding new key for %s:%s' % (server, port))
khf[hostid] = fingerprint
@@ -271,54 +414,82 @@ def attrrequested(attr, attrlist, seenattributes):
truename = candidate
if candidate.startswith('hm'):
candidate = candidate.replace('hm', 'hardwaremanagement', 1)
if candidate == attr:
if candidate in _attraliases:
candidate = _attraliases[candidate]
if fnmatch.fnmatch(attr.lower(), candidate.lower()):
seenattributes.add(truename)
return True
elif '.' not in candidate and attr.startswith(candidate + '.'):
elif attr.lower().startswith(candidate.lower() + '.'):
seenattributes.add(truename)
return True
return False
def printattributes(session, requestargs, showtype, nodetype, noderange, options):
path = '/{0}/{1}/attributes/{2}'.format(nodetype, noderange, showtype)
return print_attrib_path(path, session, requestargs, options)
def print_attrib_path(path, session, requestargs, options, rename=None, attrprefix=None):
exitcode = 0
seenattributes = set([])
for res in session.read('/{0}/{1}/attributes/{2}'.format(nodetype, noderange, showtype)):
for res in session.read(path):
if 'error' in res:
sys.stderr.write(res['error'] + '\n')
exitcode = 1
continue
for node in res['databynode']:
for attr in res['databynode'][node]:
for node in sorted(res['databynode']):
for attr, val in sorted(
res['databynode'][node].items(),
key=lambda k: k[1].get('sortid', k[0]) if isinstance(k[1], dict) else k[0]):
if attr == 'error':
sys.stderr.write('{0}: Error: {1}\n'.format(node, val))
continue
if attr == 'errorcode':
exitcode |= val
continue
seenattributes.add(attr)
if rename:
printattr = rename.get(attr, attr)
else:
printattr = attr
if attrprefix:
printattr = attrprefix + printattr
currattr = res['databynode'][node][attr]
if (requestargs is None or requestargs == [] or attrrequested(attr, requestargs, seenattributes)):
if show_attr(attr, requestargs, seenattributes, options):
if 'value' in currattr:
if currattr['value'] is not None:
val = currattr['value']
if isinstance(val, list):
val = ','.join(val)
attrout = '{0}: {1}: {2}'.format(
node, attr, currattr['value'])
node, printattr, val)
else:
attrout = '{0}: {1}:'.format(node, attr)
attrout = '{0}: {1}:'.format(node, printattr)
elif 'isset' in currattr:
if currattr['isset']:
attrout = '{0}: {1}: ********'.format(node, attr)
attrout = '{0}: {1}: ********'.format(node,
printattr)
else:
attrout = '{0}: {1}:'.format(node, attr)
attrout = '{0}: {1}:'.format(node, printattr)
elif 'broken' in currattr:
attrout = '{0}: {1}: *ERROR* BROKEN EXPRESSION: ' \
'{2}'.format(node, attr,
'{2}'.format(node, printattr,
currattr['broken'])
elif isinstance(currattr, list) or isinstance(currattr, tuple):
attrout = '{0}: {1}: {2}'.format(node, attr, ', '.join(map(str, currattr)))
attrout = '{0}: {1}: {2}'.format(node, attr, ','.join(map(str, currattr)))
elif isinstance(currattr, dict):
dictout = []
for k, v in currattr.items:
dictout.append("{0}={1}".format(k, v))
attrout = '{0}: {1}: {2}'.format(node, attr, ', '.join(map(str, dictout)))
attrout = '{0}: {1}: {2}'.format(node, printattr, ','.join(map(str, dictout)))
else:
print ("CODE ERROR" + repr(attr))
if options.blame or 'broken' in currattr:
cprint("CODE ERROR" + repr(attr))
try:
blame = options.blame
except AttributeError:
blame = False
if blame or 'broken' in currattr:
blamedata = []
if 'inheritedfrom' in currattr:
blamedata.append('inherited from group {0}'.format(
@@ -330,7 +501,42 @@ def printattributes(session, requestargs, showtype, nodetype, noderange, options
currattr['expression']))
if blamedata:
attrout += ' (' + ', '.join(blamedata) + ')'
print attrout
try:
comparedefault = options.comparedefault
except AttributeError:
comparedefault = False
if comparedefault:
try:
exclude = options.exclude
except AttributeError:
exclude = False
if ((requestargs and not exclude) or
(currattr.get('default', None) is not None and
currattr.get('value', None) is not None and
currattr['value'] != currattr['default'])):
cval = ','.join(currattr['value']) if isinstance(
currattr['value'], list) else currattr['value']
dval = ','.join(currattr['default']) if isinstance(
currattr['default'], list) else currattr['default']
cprint('{0}: {1}: {2} (Default: {3})'.format(
node, printattr, cval, dval))
else:
try:
details = options.detail
except AttributeError:
details = False
if details:
if currattr.get('help', None):
attrout += u' (Help: {0})'.format(
currattr['help'])
if currattr.get('possible', None):
try:
attrout += u' (Choices: {0})'.format(
','.join(currattr['possible']))
except TypeError:
pass
cprint(attrout)
if not exitcode:
if requestargs:
for attr in requestargs:
@@ -340,6 +546,19 @@ def printattributes(session, requestargs, showtype, nodetype, noderange, options
return exitcode
def show_attr(attr, requestargs, seenattributes, options):
try:
reverse = options.exclude
except AttributeError:
reverse = False
if requestargs is None or requestargs == []:
return True
processattr = attrrequested(attr, requestargs, seenattributes)
if reverse:
processattr = not processattr
return processattr
def printgroupattributes(session, requestargs, showtype, nodetype, noderange, options):
exitcode = 0
seenattributes = set([])
@@ -367,29 +586,18 @@ def printgroupattributes(session, requestargs, showtype, nodetype, noderange, op
attrout = '{0}: {1}: *ERROR* BROKEN EXPRESSION: ' \
'{2}'.format(noderange, attr,
currattr['broken'])
elif 'expression' in currattr:
attrout = '{0}: {1}: (will derive from expression {2})'.format(noderange, attr, currattr['expression'])
elif isinstance(currattr, list) or isinstance(currattr, tuple):
attrout = '{0}: {1}: {2}'.format(noderange, attr, ', '.join(map(str, currattr)))
attrout = '{0}: {1}: {2}'.format(noderange, attr, ','.join(map(str, currattr)))
elif isinstance(currattr, dict):
dictout = []
for k, v in currattr.items:
dictout.append("{0}={1}".format(k, v))
attrout = '{0}: {1}: {2}'.format(noderange, attr, ', '.join(map(str, dictout)))
attrout = '{0}: {1}: {2}'.format(noderange, attr, ','.join(map(str, dictout)))
else:
print ("CODE ERROR" + repr(attr))
if options.blame or 'broken' in currattr:
blamedata = []
if 'inheritedfrom' in currattr:
blamedata.append('inherited from group {0}'.format(
currattr['inheritedfrom']
))
if 'expression' in currattr:
blamedata.append(
'derived from expression "{0}"'.format(
currattr['expression']))
if blamedata:
attrout += ' (' + ', '.join(blamedata) + ')'
print attrout
cprint("CODE ERROR" + repr(attr))
cprint(attrout)
if not exitcode:
if requestargs:
for attr in requestargs:
@@ -398,7 +606,7 @@ def printgroupattributes(session, requestargs, showtype, nodetype, noderange, op
exitcode = 1
return exitcode
def updateattrib(session, updateargs, nodetype, noderange, options):
def updateattrib(session, updateargs, nodetype, noderange, options, dictassign=None):
# update attribute
exitcode = 0
if options.clear:
@@ -412,28 +620,89 @@ def updateattrib(session, updateargs, nodetype, noderange, options):
exitcode = res['errorcode']
sys.stderr.write('Error: ' + res['error'] + '\n')
sys.exit(exitcode)
elif hasattr(options, 'environment') and options.environment:
for key in updateargs[1:]:
key = key.replace('.', '_')
value = os.environ.get(
key, os.environ[key.upper()])
# Let's do one pass to make sure that there's not a usage problem
for key in updateargs[1:]:
key = key.replace('.', '_')
value = os.environ.get(
key, os.environ[key.upper()])
if (nodetype == "nodegroups"):
exitcode = session.simple_nodegroups_command(noderange,
'attributes/all',
value, key)
else:
exitcode = session.simple_noderange_command(noderange,
'attributes/all',
value, key)
sys.exit(exitcode)
elif dictassign:
for key in dictassign:
if nodetype == 'nodegroups':
exitcode = session.simple_nodegroups_command(
noderange, 'attributes/all', dictassign[key], key)
else:
exitcode = session.simple_noderange_command(
noderange, 'attributes/all', dictassign[key], key)
else:
if "=" in updateargs[1]:
try:
if len(updateargs[1:]) > 1:
for val in updateargs[1:]:
val = val.split('=')
if (nodetype == "nodegroups"):
exitcode = session.simple_nodegroups_command(noderange, 'attributes/all'.format(noderange),
val[1],val[0])
else:
exitcode = session.simple_noderange_command(noderange, 'attributes/all'.format(noderange),
val[1], val[0])
else:
val = updateargs[1].split('=')
if nodetype == "nodegroups" :
exitcode = session.simple_nodegroups_command(noderange, 'attributes/all'.format(noderange),
val[1], val[0])
for val in updateargs[1:]:
val = val.split('=', 1)
if val[0][-1] in (',', '-', '^'):
key = val[0][:-1]
if val[0][-1] == ',':
value = {'prepend': val[1]}
elif val[0][-1] in ('-', '^'):
value = {'remove': val[1]}
else:
exitcode = session.simple_noderange_command(noderange, 'attributes/all'.format(noderange),
val[1], val[0])
key = val[0]
value = val[1]
if (nodetype == "nodegroups"):
exitcode = session.simple_nodegroups_command(noderange, 'attributes/all',
value, key)
else:
exitcode = session.simple_noderange_command(noderange, 'attributes/all',
value, key)
except:
sys.stderr.write('Error: {0} not a valid expression\n'.format(str(updateargs[1:])))
exitcode = 1
sys.exit(exitcode)
return exitcode
# So we try to prevent bad things from happening when globbing
# We tried to head this off at the shell, but the various solutions would end
# up breaking the shell in various ways (breaking pipe capability if using
# DEBUG, breaking globbing if in pipe, etc)
# Then we tried to parse the original commandline instead, however shlex isn't
# going to parse full bourne language (e.g. knowing that '|' and '>' and
# a world of other things would not be in our command line
# so finally, just make sure the noderange appears verbatim in the command line
# if we glob to something, then bash will change noderange and this should
# detect it and save the user from tragedy
def check_globbing(noderange):
if not os.path.exists(noderange):
return True
rawargs = os.environ.get('CURRENT_CMDLINE', None)
if rawargs:
rawargs = shlex.split(rawargs)
for arg in rawargs:
if arg.startswith('$'):
arg = arg[1:]
if arg.endswith(';'):
arg = arg[:-1]
arg = os.environ.get(arg, '$' + arg)
if arg.startswith(noderange):
break
else:
sys.stderr.write(
'Shell glob conflict detected, specified target "{0}" '
'not in command line, but is a file. You can use "set -f" in '
'bash or change directories such that there is no filename '
'that would conflict.'
'\n'.format(noderange))
sys.exit(1)
@@ -0,0 +1,87 @@
# Copyright 2017 Lenovo
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import fcntl
import sys
import struct
import termios
def get_screenwidth():
return struct.unpack('hh', fcntl.ioctl(sys.stdout, termios.TIOCGWINSZ,
b'....'))[1]
class ScreenPrinter(object):
def __init__(self, noderange, client, textlen=4):
self.squeeze = sys.stdout.isatty()
self.textlen = textlen
self.noderange = noderange
self.client = client
self.nodeoutput = {}
self.nodelist = []
maxlen = 0
for ans in self.client.read('/noderange/{0}/nodes/'.format(noderange)):
if 'error' in ans:
sys.stderr.write(ans['error'])
continue
nodename = ans['item']['href'][:-1]
if len(nodename) > maxlen:
maxlen = len(nodename)
self.nodelist.append(nodename)
self.nodeoutput[nodename] = ''
self.nodenamelen = maxlen
self.textlen = textlen
self.fieldwidth = maxlen + textlen + 1 # 1 for column
def set_output(self, node, text):
if self.nodeoutput[node] == text:
return
self.nodeoutput[node] = text
if len(text) >= self.textlen:
self.textlen = len(text) + 1
self.fieldwidth = self.textlen + self.nodenamelen + 1
self.drawscreen()
def drawscreen(self):
if self.squeeze:
currwidth = get_screenwidth()
numfields = currwidth // self.fieldwidth
fieldformat = '{{0:>{0}}}:{{1:{1}}}'.format(self.nodenamelen,
self.textlen)
sys.stdout.write('\x1b[2J\x1b[;H') # clear screen
else:
numfields = 1
fieldformat = '{0}: {1}'
currfields = 0
for node in self.nodelist:
if currfields >= numfields:
sys.stdout.write('\n')
currfields = 1
else:
currfields += 1
sys.stdout.write(fieldformat.format(node, self.nodeoutput[node]))
sys.stdout.write('\n')
sys.stdout.flush()
if __name__ == '__main__':
import confluent.client as client
c = client.Command()
p = ScreenPrinter('n1-n13', c)
p.set_output('n3', 'Upload: 67%')
+43
View File
@@ -0,0 +1,43 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2014 IBM Corporation
# Copyright 2015-2016 Lenovo
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import re
numregex = re.compile('([0-9]+)')
def naturalize_string(key):
"""Analyzes string in a human way to enable natural sort
:param key: The node name to analyze
:returns: A structure that can be consumed by 'sorted'
"""
return [int(text) if text.isdigit() else text.lower()
for text in re.split(numregex, key)]
def natural_sort(iterable):
"""Return a sort using natural sort if possible
:param iterable:
:return:
"""
try:
return sorted(iterable, key=naturalize_string)
except TypeError:
# The natural sort attempt failed, fallback to ascii sort
return sorted(iterable)
+222
View File
@@ -0,0 +1,222 @@
# Copyright 2017 Lenovo
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import difflib
import re
import sys
try:
range = xrange
except NameError:
pass
numregex = re.compile('([0-9]+)')
def humanify_nodename(nodename):
"""Analyzes nodename in a human way to enable natural sort
:param nodename: The node name to analyze
:returns: A structure that can be consumed by 'sorted'
"""
return [int(text) if text.isdigit() else text.lower()
for text in re.split(numregex, nodename)]
def _colorize_line(orig, mask):
highlighted = False
newline = orig[0]
for i in range(1, len(orig)):
if i > len(mask) - 1:
if highlighted:
newline += '\x1b[0m'
newline += orig[i:]
break
if highlighted and mask[i] == ' ':
highlighted = False
newline += '\x1b[0m'
elif not highlighted and mask[i] != ' ':
highlighted = True
newline += '\x1b[31m'
newline += orig[i]
newline += '\x1b[0m'
return newline
def near_diff(idx, diffdata):
maxidx = idx + 3
if maxidx > len(diffdata) -1:
maxidx = len(diffdata) - 1
idx = idx - 3
if idx < 0:
idx = 0
while idx <= maxidx:
if len(diffdata[idx]) > 0 and diffdata[idx][0] in ('+', '-'):
return True
idx += 1
return False
def colordiff(first, second):
diffdata = list(difflib.ndiff(first, second))
quiet = True
for i in range(len(diffdata)):
if i < len(diffdata) - 1 and diffdata[i + 1].startswith('?'):
if quiet:
quiet = False
yield '@@'
yield _colorize_line(diffdata[i], diffdata[i + 1])
elif not diffdata[i].startswith('?') and near_diff(i, diffdata):
if quiet:
quiet = False
yield '@@'
yield diffdata[i]
elif not diffdata[i].startswith('?'):
quiet = True
class GroupedData(object):
'''A post processor to sort and compare per-node data
:param confluentconnection: If given, will attempt to use the connection to abbreviate noderanges
'''
def __init__(self, confluentconnection=None):
self.bynode = {}
self.byoutput = {}
self.header = {}
self.client = confluentconnection
def generate_byoutput(self):
self.byoutput = {}
for n in self.bynode:
output = '\n'.join(self.bynode[n])
if output not in self.byoutput:
self.byoutput[output] = set([n])
else:
self.byoutput[output].add(n)
def add_line(self, node, line):
if node not in self.bynode:
self.bynode[node] = [line]
else:
self.bynode[node].append(line)
def get_group_text(self, nodes):
if self.client:
headerkey = ','.join(sorted(nodes))
if headerkey in self.header:
return self.header[headerkey]
noderange = ''
for reply in self.client.create('/noderange//abbreviate',
{'nodes': sorted(nodes)}):
noderange = reply['noderange']
self.header[headerkey] = noderange
return noderange
else:
return ','.join(sorted(nodes, key=humanify_nodename))
def print_all(self, output=sys.stdout, skipmodal=False, reverse=False,
count=False):
self.generate_byoutput()
modaloutput = None
ismodal = True
if reverse:
outdatalist = sorted(
self.byoutput, key=lambda x: [len(self.byoutput[x]),
humanify_nodename(
self.get_group_text(
self.byoutput[x]
))])
else:
outdatalist = sorted(
self.byoutput, key=lambda x: [0 - len(self.byoutput[x]),
humanify_nodename(
self.get_group_text(
self.byoutput[x]
))])
if reverse and skipmodal:
# if reversed, the last is biggest and should be skipped if modal
outdatalist = outdatalist[:-1]
for outdata in outdatalist:
if not reverse and skipmodal:
# If big first, this makes skipmodal skip first
skipmodal = False
continue
currout = '====================================\n'
currout += self.get_group_text(self.byoutput[outdata])
currout += '\n====================================\n'
if count:
currout += 'Count: {0}'.format(len(list(
self.byoutput[outdata])))
currout += '\n====================================\n'
currout += outdata
currout += '\n\n'
output.write(currout)
output.flush()
def print_deviants(self, output=sys.stdout, skipmodal=False, reverse=False,
count=False, basenode=None):
self.generate_byoutput()
modaloutput = None
ismodal = True
revoutput = []
if basenode:
for checkout in self.byoutput:
if basenode in self.byoutput[checkout]:
modaloutput = checkout
for outdata in sorted(
self.byoutput, key=lambda x: [0 if modaloutput == x else 1,
0 - len(self.byoutput[x]),
humanify_nodename(
self.get_group_text(
self.byoutput[x]
))]):
if modaloutput is None:
modaloutput = outdata
if skipmodal:
skipmodal = False
ismodal = False
continue
currout = '====================================\n'
currout += self.get_group_text(self.byoutput[outdata])
currout += '\n====================================\n'
if count:
currout += 'Count: {0}'.format(len(list(
self.byoutput[outdata])))
currout += '\n====================================\n'
if ismodal:
ismodal = False
currout += outdata
else:
currout += '\n'.join(colordiff(modaloutput.split('\n'),
outdata.split('\n')))
currout += '\n\n'
if reverse:
revoutput.append(currout)
else:
output.write(currout)
for currout in reversed(revoutput):
output.write(currout)
output.flush()
if __name__ == '__main__':
groupoutput = GroupedData()
for line in sys.stdin.read().split('\n'):
if not line:
continue
groupoutput.add_line(*line.split(': ', 1))
groupoutput.print_deviants()
+38 -7
View File
@@ -20,6 +20,16 @@ from datetime import datetime
import json
import struct
try:
unicode
except NameError:
unicode = str
try:
range = xrange
except NameError:
pass
def decodestr(value):
ret = None
try:
@@ -29,26 +39,39 @@ def decodestr(value):
ret = value.decode('cp437')
except UnicodeDecodeError:
ret = value
except AttributeError:
return value
return ret
def unicode_dictvalues(dictdata):
for key in dictdata:
if isinstance(dictdata[key], str):
if isinstance(dictdata[key], bytes):
dictdata[key] = decodestr(dictdata[key])
elif isinstance(dictdata[key], datetime):
dictdata[key] = dictdata[key].strftime('%Y-%m-%dT%H:%M:%S')
elif isinstance(dictdata[key], list):
for i in xrange(len(dictdata[key])):
if isinstance(dictdata[key][i], str):
dictdata[key][i] = decodestr(dictdata[key][i])
elif isinstance(dictdata[key][i], dict):
unicode_dictvalues(dictdata[key][i])
_unicode_list(dictdata[key])
elif isinstance(dictdata[key], dict):
unicode_dictvalues(dictdata[key])
def _unicode_list(currlist):
for i in range(len(currlist)):
if isinstance(currlist[i], str):
currlist[i] = decodestr(currlist[i])
elif isinstance(currlist[i], dict):
unicode_dictvalues(currlist[i])
elif isinstance(currlist[i], list):
_unicode_list(currlist[i])
def send(handle, data):
if isinstance(data, str):
if isinstance(data, unicode):
try:
data = data.encode('utf-8')
except AttributeError:
pass
if isinstance(data, bytes) or isinstance(data, unicode):
# plain text, e.g. console data
tl = len(data)
if tl == 0:
@@ -74,6 +97,14 @@ def send(handle, data):
handle.sendall(struct.pack("!I", tl))
handle.sendall(sdata)
def recvall(handle, size):
rd = handle.recv(size)
while len(rd) < size:
nd = handle.recv(size - len(rd))
if not nd:
raise Exception("Error reading data")
rd += nd
return rd
def recv(handle):
tl = handle.recv(4)
+10 -2
View File
@@ -24,10 +24,18 @@ a confluent server.
%setup -n %{name}-%{version} -n %{name}-%{version}
%build
python setup.py build
%if "%{dist}" == ".el8"
python3 setup.py build
%else
python2 setup.py build
%endif
%install
python setup.py install --single-version-externally-managed -O1 --root=$RPM_BUILD_ROOT --record=INSTALLED_FILES --install-scripts=/opt/confluent/bin --install-purelib=/opt/confluent/lib/python
%if "%{dist}" == ".el8"
python3 setup.py install --single-version-externally-managed -O1 --root=$RPM_BUILD_ROOT --record=INSTALLED_FILES --install-scripts=/opt/confluent/bin --install-purelib=/opt/confluent/lib/python
%else
python2 setup.py install --single-version-externally-managed -O1 --root=$RPM_BUILD_ROOT --record=INSTALLED_FILES --install-scripts=/opt/confluent/bin --install-purelib=/opt/confluent/lib/python
%endif
%clean
+283
View File
@@ -1,2 +1,285 @@
PATH=/opt/confluent/bin:$PATH
export PATH
MANPATH=/opt/confluent/share/man:$MANPATH
export MANPATH
# The aliases below are to signify that file globbing is unwelcome at the shell
# this avoids a problem if a user does a noderange like 'n[21-33] and there is a file
# in the directory like 'n3' that causes the parameter to change and target a totally
# different node
# Unfortunately in bourne shell, we cannot reliably ensure a prepended set-f
# and an appended set +f are both run. alias seems to be the only mechanism
# that can intervene before glob expansion, but it lacks power.
# putting it into a function to append is all well and good, *except* that
# if doing something like 'nodepower compute|grep' causes set -f to execute
# in current shell, and the function to be in a subshell and leaves globbing
# disabled in the parent shell. Instead, store the current command in a
# variable and use that to check for misglobbed noderanges, which was the goal
alias nodeattrib='CURRENT_CMDLINE=$(HISTTIMEFORMAT= builtin history 1); export CURRENT_CMDLINE; nodeattrib'
alias nodebmcreset='CURRENT_CMDLINE=$(HISTTIMEFORMAT= builtin history 1); export CURRENT_CMDLINE; nodebmcreset'
alias nodeboot='CURRENT_CMDLINE=$(HISTTIMEFORMAT= builtin history 1); export CURRENT_CMDLINE; nodeboot'
alias nodeconfig='CURRENT_CMDLINE=$(HISTTIMEFORMAT= builtin history 1); export CURRENT_CMDLINE; nodeconfig'
alias nodeconsole='CURRENT_CMDLINE=$(HISTTIMEFORMAT= builtin history 1); export CURRENT_CMDLINE; nodeconsole'
alias nodedefine='CURRENT_CMDLINE=$(HISTTIMEFORMAT= builtin history 1); export CURRENT_CMDLINE; nodedefine'
alias nodeeventlog='CURRENT_CMDLINE=$(HISTTIMEFORMAT= builtin history 1); export CURRENT_CMDLINE; nodeeventlog'
alias nodefirmware='CURRENT_CMDLINE=$(HISTTIMEFORMAT= builtin history 1); export CURRENT_CMDLINE; nodefirmware'
alias nodegroupattrib='CURRENT_CMDLINE=$(HISTTIMEFORMAT= builtin history 1); export CURRENT_CMDLINE; nodegroupattrib'
alias nodegroupdefine='CURRENT_CMDLINE=$(HISTTIMEFORMAT= builtin history 1); export CURRENT_CMDLINE; nodegroupdefine'
alias nodegroupremove='CURRENT_CMDLINE=$(HISTTIMEFORMAT= builtin history 1); export CURRENT_CMDLINE; nodegroupremove'
alias nodehealth='CURRENT_CMDLINE=$(HISTTIMEFORMAT= builtin history 1); export CURRENT_CMDLINE; nodehealth'
alias nodeidentify='CURRENT_CMDLINE=$(HISTTIMEFORMAT= builtin history 1); export CURRENT_CMDLINE; nodeidentify'
alias nodeinventory='CURRENT_CMDLINE=$(HISTTIMEFORMAT= builtin history 1); export CURRENT_CMDLINE; nodeinventory'
alias nodelist='CURRENT_CMDLINE=$(HISTTIMEFORMAT= builtin history 1); export CURRENT_CMDLINE; nodelist'
alias nodemedia='CURRENT_CMDLINE=$(HISTTIMEFORMAT= builtin history 1); export CURRENT_CMDLINE; nodemedia'
alias nodepower='CURRENT_CMDLINE=$(HISTTIMEFORMAT= builtin history 1); export CURRENT_CMDLINE; nodepower'
alias noderemove='CURRENT_CMDLINE=$(HISTTIMEFORMAT= builtin history 1); export CURRENT_CMDLINE; noderemove'
alias nodereseat='CURRENT_CMDLINE=$(HISTTIMEFORMAT= builtin history 1); export CURRENT_CMDLINE; nodereseat'
alias noderun='CURRENT_CMDLINE=$(HISTTIMEFORMAT= builtin history 1); export CURRENT_CMDLINE; noderun'
alias nodesensors='CURRENT_CMDLINE=$(HISTTIMEFORMAT= builtin history 1); export CURRENT_CMDLINE; nodesensors'
alias nodesetboot='CURRENT_CMDLINE=$(HISTTIMEFORMAT= builtin history 1); export CURRENT_CMDLINE; nodesetboot'
alias nodestorage='CURRENT_CMDLINE=$(HISTTIMEFORMAT= builtin history 1); export CURRENT_CMDLINE; nodestorage'
alias nodeshell='CURRENT_CMDLINE=$(HISTTIMEFORMAT= builtin history 1); export CURRENT_CMDLINE; nodeshell'
alias nodelicense='CURRENT_CMDLINE=$(HISTTIMEFORMAT= builtin history 1); export CURRENT_CMDLINE; nodelicense'
# Do not continue for non-bash shells, the rest of this sets up bash completion functions
[ -z "$BASH_VERSION" -o -z "$PS1" ] && return
_confluent_get_args()
{
CMPARGS=($COMP_LINE)
NUMARGS=$((COMP_CWORD+1))
if [ "${COMP_WORDS[COMP_CWORD]}" == '' ]; then
CMPARGS+=("")
fi
GENNED=""
for CAND in ${COMP_CANDIDATES[@]}; do
candarray=(${CAND//,/ })
matched=0
for c in "${candarray[@]}"; do
for arg in "${CMPARGS[@]}"; do
if [ "$arg" = "$c" ]; then
matched=1
break
fi
done
done
if [ 0 = $matched ]; then
for c in "${candarray[@]}"; do
GENNED+=" $c"
done
fi
done
}
function _confluent_generic_completion()
{
_confluent_get_args
if [ $NUMARGS -ge 3 ] && [ ! -z "$GENNED" ]; then
COMPREPLY=($(compgen -W "$GENNED" -- ${COMP_WORDS[COMP_CWORD]}))
fi
if [ $NUMARGS -lt 3 ]; then
_confluent_nr_completion
return;
fi
}
_confluent_nodeidentify_completion()
{
COMP_CANDIDATES=("on,off,blink -h")
_confluent_generic_completion
}
_confluent_nodesetboot_completion()
{
COMP_CANDIDATES=("default,cd,network,setup,hd -h -b -p")
_confluent_generic_completion
}
_confluent_nodepower_completion()
{
COMP_CANDIDATES=("boot,off,on,status -h -p")
_confluent_generic_completion
}
_confluent_nodemedia_completion()
{
COMP_CANDIDATES=("list,upload,attach,detachall -h")
_confluent_get_args
if [ $NUMARGS -gt 3 ] && [ ${CMPARGS[-2]} == 'upload' ]; then
compopt -o default
COMPREPLY=()
return
fi
if [ $NUMARGS -ge 3 ] && [ ! -z "$GENNED" ]; then
COMPREPLY=($(compgen -W "$GENNED" -- ${COMP_WORDS[COMP_CWORD]}))
return;
fi
if [ $NUMARGS -lt 3 ]; then
_confluent_nr_completion
return;
fi
}
_confluent_nodefirmware_completion()
{
_confluent_get_args
if [ $NUMARGS == 3 ]; then
COMPREPLY=($(compgen -W "list update" -- ${COMP_WORDS[COMP_CWORD]}))
return;
fi
if [ $NUMARGS -gt 3 ] && [ ${CMPARGS[2]} == 'update' ]; then
compopt -o default
COMPREPLY=()
return
fi
if [ $NUMARGS -lt 3 ]; then
_confluent_nr_completion
return;
fi
}
_confluent_nodeshell_completion()
{
_confluent_get_args
if [ $NUMARGS == 3 ]; then
COMPREPLY=($(compgen -c -- ${COMP_WORDS[COMP_CWORD]}))
return
fi
if [ $NUMARGS -gt 3 ]; then
compopt -o default
COMPREPLY=()
return
fi
if [ $NUMARGS -lt 3 ]; then
_confluent_nr_completion
return;
fi
}
_confluent_nodelicense_completion()
{
_confluent_get_args
if [ $NUMARGS == 3 ]; then
COMPREPLY=($(compgen -W "install list save delete" -- ${COMP_WORDS[COMP_CWORD]}))
return;
fi
if [ $NUMARGS == 4 ] && [ ${CMPARGS[2]} == 'install' ]; then
compopt -o default
COMPREPLY=()
return
fi
if [ $NUMARGS == 4 ] && [ ${CMPARGS[2]} == 'save' ]; then
compopt -o dirnames
COMPREPLY=()
return
fi
if [ $NUMARGS -lt 3 ]; then
_confluent_nr_completion
return
fi
}
_confluent_nodesupport_completion()
{
_confluent_get_args
if [ $NUMARGS == 3 ]; then
COMPREPLY=($(compgen -W "servicedata" -- ${COMP_WORDS[COMP_CWORD]}))
return;
fi
if [ $NUMARGS == 4 ] && [ ${CMPARGS[2]} == 'servicedata' ]; then
compopt -o dirnames
COMPREPLY=()
return
fi
if [ $NUMARGS -lt 3 ]; then
_confluent_nr_completion
return
fi
}
_confluent_nodeattrib_completion()
{
COMP_CANDIDATES=$(nodeattrib '~.>1' all | awk '{print $2}'|sed -e 's/://')
_confluent_generic_completion
}
_confluent_nn_completion()
{
_confluent_get_args
if [ $NUMARGS -gt 2 ]; then
return;
fi
INPUT=${COMP_WORDS[COMP_CWORD]}
INPUT=${INPUT##*,-}
INPUT=${INPUT##*,}
INPUT=${INPUT##*@}
PREFIX=""
if [ "$INPUT" != "${COMP_WORDS[COMP_CWORD]}" ]; then
PREFIX=${COMP_WORDS[COMP_CWORD]}
PREFIX=$(echo $PREFIX | sed -e 's/,[^,@-]*$/,/' -e 's/,-[^,@]*$/,-/' -e 's/@[^,@]*/@/')
fi
COMPREPLY=($(compgen -W "$(nodelist | sed -e s/^/$PREFIX/)" -- "${COMP_WORDS[COMP_CWORD]}"))
}
_confluent_nr_completion()
{
CMPARGS=($COMP_LINE)
_confluent_get_args
if [ $NUMARGS -gt 2 ]; then
return;
fi
INPUT=${COMP_WORDS[COMP_CWORD]}
INPUT=${INPUT##*,-}
INPUT=${INPUT##*,}
INPUT=${INPUT##*@}
PREFIX=""
if [ "$INPUT" != "${COMP_WORDS[COMP_CWORD]}" ]; then
PREFIX=${COMP_WORDS[COMP_CWORD]}
PREFIX=$(echo $PREFIX | sed -e 's/,[^,@-]*$/,/' -e 's/,-[^,@]*$/,-/' -e 's/@[^,@]*/@/')
fi
COMPREPLY=($(compgen -W "$(confetty show /nodegroups|sed -e 's/\///' -e s/^/$PREFIX/;nodelist | sed -e s/^/$PREFIX/)" -- "${COMP_WORDS[COMP_CWORD]}"))
}
_confluent_ng_completion()
{
_confluent_get_args
if [ $NUMARGS -gt 2 ]; then
return;
fi
INPUT=${COMP_WORDS[COMP_CWORD]}
INPUT=${INPUT##*,-}
INPUT=${INPUT##*,}
INPUT=${INPUT##*@}
PREFIX=""
if [ "$INPUT" != "${COMP_WORDS[COMP_CWORD]}" ]; then
PREFIX=${COMP_WORDS[COMP_CWORD]}
PREFIX=$(echo $PREFIX | sed -e 's/,[^,@-]*$/,/' -e 's/,-[^,@]*$/,-/' -e 's/@[^,@]*/@/')
fi
COMPREPLY=($(compgen -W "$(confetty show /nodegroups|sed -e 's/\///' -e s/^/$PREFIX/)" -- "${COMP_WORDS[COMP_CWORD]}"))
}
complete -F _confluent_nodeattrib_completion nodeattrib
complete -F _confluent_nodeattrib_completion nodegroupattrib
complete -F _confluent_nr_completion nodebmcreset
complete -F _confluent_nodesetboot_completion nodeboot
complete -F _confluent_nr_completion nodeconfig
complete -F _confluent_nn_completion nodeconsole
complete -F _confluent_nr_completion nodeeventlog
complete -F _confluent_nodefirmware_completion nodefirmware
complete -F _confluent_ng_completion nodegroupattrib
complete -F _confluent_ng_completion nodegroupremove
complete -F _confluent_nr_completion nodehealth
complete -F _confluent_nodeidentify_completion nodeidentify
complete -F _confluent_nr_completion nodeinventory
complete -F _confluent_nodeattrib_completion nodelist
complete -F _confluent_nodemedia_completion nodemedia
complete -F _confluent_nodepower_completion nodepower
complete -F _confluent_nr_completion noderemove
complete -F _confluent_nr_completion nodereseat
complete -F _confluent_nodeshell_completion noderun
complete -F _confluent_nr_completion nodesensors
complete -F _confluent_nodesetboot_completion nodesetboot
complete -F _confluent_nodeshell_completion nodeshell
complete -F _confluent_nodesupport_completion nodesupport
complete -F _confluent_nodelicense_completion nodelicense
+1
View File
@@ -0,0 +1 @@
for i in *.ronn; do echo -n `head -n 1 $i|awk '{print $1}'`; echo " $i"; done > index.txt
+92
View File
@@ -0,0 +1,92 @@
collate(1) -- Organize text input by node
==============================
## SYNOPSIS
`<other command> | collate [-a] [-d] [-w] [-s] [-c] [-r] [-l lognametemplate]`
## DESCRIPTION
**collate** takes input in the form of <nodename>: <data> and groups
the output for each <nodename> together, and checks for identical data to further group nodes together.
Output groups are sorted in descending size such that the topmost group is the largest, and the
last output group is the smallest. In the event of equally sized output groups,
the groups are sorted alphanumerically by their header, and each header has
node and group names sorted alphanumerically.
## OPTIONS
* `-a`, `--abbreviate`:
Use confluent to attempt to shorten the noderange. This can help identify
when output differs along a telling group boundary. For example, if
output suggests a large number of nodes are unreachable, abbreviate
showing 'rack1' as being unreachable may make more obvious a possible cause.
* `-d`, `--diff`:
Express all but the most common result group in terms of diff from
the most common result group
* `-l`, `--log`:
Save output per node to individual log files, replacing {node} in the name
with the nodename of each
* `-w`, `--watch`:
Update results dynamically as data becomes available, rather than
waiting for the command to fully complete.
* `-s`, `--skipcommon`:
Suppress printing of the most common result text group. This is used to
focus on stray output against a well known and expected result.
* `-c`, `--count`:
Print a count of the number of nodes in an output group under the
noderange.
* `-r`, `--reverse`:
Rather than starting with most common to least common, start with
the least common and print the most common last.
## EXAMPLES
* Organizing power state of multiple nodes:
`# nodepower n1-n12 | collate`
`====================================`
`n1,n2,n3,n4,n7,n8,n9,n10,n11,n12`
`====================================`
`on`
` `
`====================================`
`n5,n6`
`====================================`
`off`
* Using diff to detect distinct UEFI configuration
`# pasu n1-n4 show Processors|collate -d -s`
`====================================`
`n3`
`====================================`
`@@`
` Processors.ProcessorPerformanceStates=Enable`
` Processors.C-States=Enable`
` Processors.PackageACPIC-StateLimit=ACPI C3`
`- Processors.C1EnhancedMode=Enable`
`+ Processors.C1EnhancedMode=Disable`
`- Processors.Hyper-Threading=Enable`
`+ Processors.Hyper-Threading=Disable`
` Processors.ExecuteDisableBit=Enable`
` Processors.IntelVirtualizationTechnology=Enable`
` `
`====================================`
`n1`
`====================================`
`@@`
` Processors.ProcessorPerformanceStates=Enable`
` Processors.C-States=Enable`
` Processors.PackageACPIC-StateLimit=ACPI C3`
`- Processors.C1EnhancedMode=Enable`
`+ Processors.C1EnhancedMode=Disable`
` Processors.Hyper-Threading=Enable`
` Processors.ExecuteDisableBit=Enable`
+55
View File
@@ -0,0 +1,55 @@
collective(1) -- Check and manage a confluent collective
==============================
## SYNOPSIS
`collective invite <server>`
`collective join <server> [-i TOKEN]`
`collective show`
`collective gencert`
## DESCRIPTION
**collective** helps manage the collective mode of confluent, where multiple
confluent servers are linked together to act as one. For example, the procedure to set up
a collective to run on three servers called mgt1, mgt2, and mgt3, first install and start
confluent as usual on the three servers. On mgt1, run `collective invite mgt2` and an
invitation token will be output. On mgt2, either run `collective join mgt1` to paste
the token interactively, or `collective join mgt1 -i <token>`. At this point, either
mgt1 or mgt2 can bring in mgt3. For example on mgt2 run `collective invite mgt3` and
on mgt3 run `collective join mgt2 -i <token>`
This can be linked together in the following manner with ssh:
on mgt1:
`# ssh mgt2 collective join mgt1 -i $(collective invite mgt2)`
Note that a collective is only redundant with 3 or more members. The collective
will function so long as more than half of the members are online. A collective
of two members is supported, but without redundancy.
Also note that the collective leader role is dynamic, but has no impact on interacting
with confluent. It is merely an internal role that can dynamically change depending
on circumstances.
## OPTIONS
* `-i`:
Provide the token as an argument rather than interactively.
## EXAMPLES
* Inviting a server called mgt2:
`# collective invite mgt2`
`bWd0MkA+BNQ6XAxMXlqJJa+EQRlihL/k9xCXnasgSQXZr989Pa1/ln7G3e1Ncxx6BMzMqqreHJVkPr2FrzjNit/UgHlg`
* On mgt2, joining mgt1:
`# collective join mgt1 -i bWd0MkA+BNQ6XAxMXlqJJa+EQRlihL/k9xCXnasgSQXZr989Pa1/ln7G3e1Ncxx6BMzMqqreHJVkPr2FrzjNit/UgHlg`
`Success`
* Showing the collective state:
`# collective show`
`Quorum: True`
`Leader: mgt1`
`Active collective members:`
` mgt2`
+3 -4
View File
@@ -1,9 +1,10 @@
confetty(1) --- Interactive confluent client
confetty(8) --- Interactive confluent client
=================================================
## SYNOPSIS
`confetty`
`confetty`
`confetty <confetty command line>`
## DESCRIPTION
@@ -33,5 +34,3 @@ commands.
Start a console session indicated by **ELEMENT** (e.g. /nodes/n1/console/session)
* `rm` **ELEMENT**
Request removal of an element. (e.g. rm events/hardware/log clears log from a node)
+14
View File
@@ -0,0 +1,14 @@
confluent(8) -- Start the confluent server
=========================================================
## SYNOPSIS
`confluent`
## DESCRIPTION
**confluent** is the name of the server daemon. It is normally run
through the init subsystem rather than executed directly. All confluent
commands connect to confluent daemon. It provides the web interface, debug,
and unix socket connectivity.
@@ -0,0 +1,26 @@
confluentdbutil(8) -- Backup or restore confluent database
=========================================================
## SYNOPSIS
`confluentdbutil [options] <dump|restore> <path>`
## DESCRIPTION
**confluentdbutil** is a utility to export/import the confluent attributes
to/from json files. The path is a directory that holds the json version.
In order to perform restore, the confluent service must not be running. It
is required to indicate how to treat the usernames/passwords are treated in
the json files (password protected, removed from the files, or unprotected).
## OPTIONS
* `-p`, `--password`:
If specified, information such as usernames and passwords will be encrypted
using the given password.
* `-r`, `--redact`:
Indicates to replace usernames and passwords with a dummy string rather
than included.
* `-u`, `--unprotected`:
The keys.json file will include the encryption keys without any protection.
+70 -43
View File
@@ -1,75 +1,102 @@
nodeattrib(1) -- List or change confluent nodes attributes
nodeattrib(8) -- List or change confluent nodes attributes
=========================================================
## SYNOPSIS
`nodeattrib` `noderange` [ current | all ]
`nodeattrib` `noderange` [-b] [<nodeattribute>...]
`nodeattrib` `noderange` [<nodeattribute1=value1> <nodeattribute2=value2> ...]
`nodeattrib` `noderange` [-c] [<nodeattribute1> <nodeattribute2=value2> ...]
`nodeattrib [-b] <noderange> [all|<nodeattribute>...]`
`nodeattrib <noderange> [<nodeattribute1=value1> <nodeattribute2=value2> ...]`
`nodeattrib -c <noderange> <nodeattribute1> <nodeattribute2> ...`
`nodeattrib -e <noderange> <nodeattribute1> <nodeattribute2> ...`
`nodeattrib -p <noderange> <nodeattribute1> <nodeattribute2> ...`
## DESCRIPTION
**nodeattrib** queries the confluent server to get information about nodes. In
**nodeattrib** manages the attributes of confluent nodes. In
the simplest form, it simply takes the given noderange(5) and lists the
matching nodes, one line at a time.
If a list of node attribute names are given, the value of those are also
displayed. If `-b` is specified, it will also display information on
how inherited and expression based attributes are defined. There is more
information on node attributes in nodeattributes(5) man page.
If `-c` is specified, this will set the nodeattribute to a null valid.
how inherited and expression based attributes are defined. Attributes can be
straightforward values, or an expression as documented in nodeattribexpressions(5).
For a full list of attributes, run `nodeattrib <node> all` against a node.
If `-c` is specified, this will set the nodeattribute to a null value.
This is different from setting the value to an empty string.
Attributes may be specified by wildcard, for example `net.*switch` will report
all attributes that begin with `net.` and end with `switch`.
If the word all is specified, then all available attributes are given.
Omitting any attribute name or the word 'all' will display only attributes
that are currently set.
For the `groups` attribute, it is possible to add a group by doing
`groups,=<newgroup>` and to remove by doing `groups^=<oldgroup>`
Note that `nodeattrib <group>` will likely not provide the expected behavior.
See nodegroupattrib(8) command on how to manage attributes on a group level.
## OPTIONS
* `-b`, `--blame`:
Annotate inherited and expression based attributes to show their base value.
* `-c`, `--clear`:
Clear given nodeattributes since '' is not the same as empty
Clear specified nodeattributes
* `-e`, `--environment`:
Set specified attributes based on exported environment variable of matching name. Environment variable names may be lower case or all upper case. Replace . with _ as needed (e.g. info.note may be specified as either $info_note or $INFO_NOTE
* `-p`, `--prompt`:
Request interactive prompting to provide values rather than the command line or environment variables.
## EXAMPLES
* Listing matching nodes of a simple noderange:
`# nodeattrib n1-n2`
`n1`: console.method: ipmi
`n1`: hardwaremanagement.manager: 172.30.3.1
`n2`: console.method: ipmi
`n2`: hardwaremanagement.manager: 172.30.3.2
`# nodeattrib n1-n2`
`n1: console.method: ipmi`
`n1: hardwaremanagement.manager: 172.30.3.1`
`n2: console.method: ipmi`
`n2: hardwaremanagement.manager: 172.30.3.2`
* Getting an attribute of nodes matching a noderange:
`# nodeattrib n1,n2 hardwaremanagement.manager`
`n1: hardwaremanagement.manager: 172.30.3.1`
`n2: hardwaremanagement.manager: 172.30.3.2`
`# nodeattrib n1,n2 hardwaremanagement.manager`
`n1: hardwaremanagement.manager: 172.30.3.1`
`n2: hardwaremanagement.manager: 172.30.3.2`
* Getting a group of attributes while determining what group defines them:
`# nodeattrib n1,n2 hardwaremanagement --blame`
`n1: hardwaremanagement.manager: 172.30.3.1`
`n1: hardwaremanagement.method: ipmi (inherited from group everything)`
`n1: hardwaremanagement.switch: r8e1`
`n1: hardwaremanagement.switchport: 14`
`n2: hardwaremanagement.manager: 172.30.3.2`
`n2: hardwaremanagement.method: ipmi (inherited from group everything)`
`n2: hardwaremanagement.switch: r8e1`
`n2: hardwaremanagement.switchport: 2`
`# nodeattrib n1,n2 hardwaremanagement --blame`
`n1: hardwaremanagement.manager: 172.30.3.1`
`n1: hardwaremanagement.method: ipmi (inherited from group everything)`
`n1: hardwaremanagement.switch: r8e1`
`n1: hardwaremanagement.switchport: 14`
`n2: hardwaremanagement.manager: 172.30.3.2`
`n2: hardwaremanagement.method: ipmi (inherited from group everything)`
`n2: hardwaremanagement.switch: r8e1`
`n2: hardwaremanagement.switchport: 2`
* Listing matching nodes of a simple noderange that are set:
`# nodeattrib n1-n2 current`
`n1`: console.method: ipmi
`n1`: hardwaremanagement.manager: 172.30.3.1
`n2`: console.method: ipmi
`n2`: hardwaremanagement.manager: 172.30.3.2
* Listing matching nodes of a simple noderange that are set:
`# nodeattrib n1-n2 current`
`n1: console.method: ipmi`
`n1: hardwaremanagement.manager: 172.30.3.1`
`n2: console.method: ipmi`
`n2: hardwaremanagement.manager: 172.30.3.2`
* Change attribute on nodes of a simple noderange:
`# nodeattrib n1-n2 console.method=serial`
`n1`: console.method: serial
`n1`: hardwaremanagement.manager: 172.30.3.1
`n2`: console.method: serial
`n2`: hardwaremanagement.manager: 172.30.3.2
* Change attribute on nodes of a simple noderange:
`# nodeattrib n1-n2 console.method=serial`
`n1: console.method: serial`
`n1: hardwaremanagement.manager: 172.30.3.1`
`n2: console.method: serial`
`n2: hardwaremanagement.manager: 172.30.3.2`
* Clear attribute on nodes of a simple noderange, if you want to retain the variable set the attribute to "":
`# nodeattrib n1-n2 -c console.method`
`# nodeattrib n1-n2 console.method`
Error: console.logging not a valid attribute
* Clear attribute on nodes of a simple noderange, if you want to retain the variable set the attribute to "":
`# nodeattrib n1-n2 -c console.method`
`# nodeattrib n1-n2 console.method`
`n1: console.method: `
`n2: console.method: `
* List all switches that a node is described as connected to:
`# nodeattrib d1 net.*switch`
`d1: net.mgt.switch: mgtswitch1`
`d1: net.pxe.switch: pxeswitch1`
`d1: net.switch:`
## SEE ALSO
nodegroupattrib(8), nodeattribexpressions(5)
@@ -0,0 +1,76 @@
nodeattribexpressions(5) -- Confluent attribute expression syntax
=================================================================
## DESCRIPTION
In confluent, any attribute may either be a straightforward value, or an
expression to generate the value.
An expression will contain some directives wrapped in `{}` characters. Within
`{}` are a number of potential substitute values and operations.
Note that syntax of expressions can have overlap with the shell syntax.
For example:
`$ echo (n2)`
`-bash: syntax error near unexpected token `n2'`
In such a case, it helps to quote the expression to allow it to be passed:
`$ echo '(n2)'`
`(n2)`
The most common operation is to extract a number from the nodename. These
values are available as n1, n2, etc. So for example attributes for a node named
b1o2r3u4 would have {n1} as 1, {n2} as 2, {n3} as 3, and {n4} as 4.
Additionally, {n0} is special as representing the last number in a name, so in
the b1o2r3u4 example, {n0} would be 4.
Frequently a value derives from a number in the node name, but must undergo a
transform to be useful. As an example, if we have a scheme where nodes are
numbered n1-n512, and they are arranged 1-42 in rack1, 43-84 in rack2, and so
forth, it is convenient to perform arithmetic on the extracted number. Here is
an example of codifying the above scheme, and setting the u to the remainder:
`location.rack=rack{(n1-1)/42+1}`
`location.u={(n1-1)%42+1}`
Note how text may be mixed into expressions, only data within {} will receive
special treatment. Here we also had to adjust by subtracting 1 and adding it
back to make the math work as expected.
It is sometimes the case that the number must be formatted a different way,
either specifying 0 padding or converting to hexadecimal. This can be done by a
number of operators at the end to indicate formatting changes.
`{n1:02x} - Zero pad to two decimal places, and convert to hexadecimal, as mightbe used for generating MAC addresses`
`{n1:x} - Hexadecimal without padding, as may be used in a generated IPv6 address`
`{n1:X} - Uppercase hexadecimal`
`{n1:02d} - Zero pad a normal numeric representation of the number.`
Another common element to pull into an expression is the node name in whole:
`hardwaremanagement.manager={node}-imm`
Additionally other attributes may be pulled in:
`hardwaremanagement.switchport={location.u}`
Multiple expressions are permissible within a single attribute:
`hardwaremanagement.manager={node}-{hardwaremanagement.method}`
A note to developers: in general the API layer will automatically recognize a
generic set attribute to string with expression syntax and import it as an
expression. For example, submitting the following JSON:
`{ 'location.rack': '{n1}' }`
Will auto-detect {n1} as an expression and assign it normally. If wanting to
set that value verbatim, it can either be escaped by doubling the {} or by
explicitly declaring it as a value:
`{ 'location.rack': '{{n1}}' }`
`{ 'location.rack': { 'value': '{n1}' } }`
@@ -0,0 +1,19 @@
nodebmcreset(8) -- Reset management controller
=========================================================
## SYNOPSIS
`nodebmcreset <noderange>`
## DESCRIPTION
`nodebmcreset` allows you to reset the management controller of the specified noderange
## EXAMPLES:
* Reset the management controller for nodes n1 through n4:
`# nodebmcreset n1-n4`
`n1: BMC Reset Successful`
`n2: BMC Reset Successful`
`n3: BMC Reset Successful`
`n4: BMC Reset Successful`
+66
View File
@@ -0,0 +1,66 @@
nodeboot(8) -- Reboot a confluent node to a specific device
=========================================================
## SYNOPSIS
`nodeboot <noderange>`
`nodeboot [options] <noderange>` [default|cd|network|setup|hd]
## DESCRIPTION
**nodeboot** reboots nodes in a noderange. If an additional argument is given,
it sets the node to specifically boot to that as the next boot. This
performs an immediate reboot without waiting for the OS. To set the boot
device without inducing a reboot, see the `nodesetboot` command.
## OPTIONS
* `-b`, `--bios`:
For a system that supports both BIOS and UEFI style boot, request BIOS style
boot if supported (some platforms will UEFI boot with this flag anyway).
* `-u`, `--uefi`:
This flag does nothing, it is for command compatibility with xCAT's rsetboot
* `-p`, `--persist`:
For a system that supports it, mark the boot override to persist rather than
be a one time change. Many systems do not support this functionality.
* `default`:
Request a normal default boot with no particular device override
* `cd`:
Request boot from media. Note that this can include physical CD,
remote media mounted as CD/DVD, and detachable hard disks drives such as usb
key devices.
* `network`:
Request boot to network
* `setup`:
Request to enter the firmware configuration menu (e.g. F1 setup) on next boot.
* `hd`:
Boot straight to hard disk drive
## EXAMPLES
* Booting n3 and n4 to the default boot behavior:
`# nodeboot n3-n4`
`n3: default`
`n4: default`
`n3: on->reset`
`n4: on->reset`
* Booting n1 and n2 to setup menu:
`# nodeboot n1-n2 setup`
`n2: setup`
`n1: setup`
`n2: on->reset`
`n1: on->reset`
* Booting n3 and n4 to network:
`# nodeboot n3-n4 net`
`n3: network`
`n4: network`
`n4: on->reset`
`n3: off->on`
+58
View File
@@ -0,0 +1,58 @@
nodeconfig(8) -- Show or change node configuration
==================================================
## SYNOPSIS
`nodeconfig <noderange> [options] [<configuration>..]`
`nodeconfig <noderange> [options] [<configuration=value>..]`
## DESCRIPTION
**nodeconfig** manages the configuration of nodes managed by confluent.
Rather than manipulating the confluent database, this actually modifies the
running configuration on the node firmware. Calling without '=' will show the
current value, and '=' will change the value. Network information can be
given as a node expression, as documented in the man page for nodeattribexpressions(5).
## OPTIONS
* `-c`, `--comparedefault`:
Take the given settings and compare against default value, if available. If
no configuration values are specified, it will show only those that differ.
If combined with `-x`, will show all differing values except those indicated
by `-x`
* `-x`, `--exclude`:
Rather than listing only the specified configuration parameters, list all
attributes except for the specified ones
* `-d`, `--detail`:
Provide detailed data as available. This can include help text and valid
values for a setting.
* `-r`, `--restoredefault`:
Request that the specified component of the targeted nodes will have its
configuration reset to default. Currently the only component implemented
is uefi.
* `-b`, '--batch':
Provide arguments as lines of a file, rather than the command line.
## EXAMPLES
* Showing the current IP configuration of noderange BMC/IMM/XCC:
`# nodeconfig s3,s4 bmc`
`s3: bmc.ipv4_address: 172.30.254.193/16`
`s3: bmc.ipv4_method: DHCP`
`s3: bmc.ipv4_gateway: 172.30.0.6`
`s4: bmc.ipv4_address: 172.30.254.192/16`
`s4: bmc.ipv4_method: DHCP`
`s4: bmc.ipv4_gateway: 172.30.0.6`
* Changing nodes `s3` and `s4` to have the ip addressess 10.1.2.3 and 10.1.2.4 with a 16 bit subnet mask:
`# nodeconfig s3,s4 bmc.ipv4_address=10.1.2.{n1}/16`
## SEE ALSO
nodeattribexpressions(5)
+38 -5
View File
@@ -1,16 +1,27 @@
nodeconsole(1) -- Open a console to a confluent node
nodeconsole(8) -- Open a console to a confluent node
=====================================================
## SYNOPSIS
`nodeconsole` `node`
`nodeconsole [options] <noderange>`
## DESCRIPTION
**nodeconsole** opens an interactive console session to a given node. This is the
text or serial console of a system. Exiting is done by hitting `Ctrl-e`, then `c`,
then `.`. Note that console output by default is additionally logged to
then `.`. Note that console output by default is additionally logged to
`/var/log/confluent/consoles/`**NODENAME**.
When the console connection to the target is broken, then confluent on backend
will initiate an automatic retry interval that is randomized between 2 and 4 minutes.
The reopen escape sequence below requests an immediate retry, as does connecting
a new session.
## OPTIONS
* `-t`, `--tile`:
Use tmux to arrange consoles of the given noderange into a tiled layout on
the terminal screen
## ESCAPE SEQUENCE COMMANDS
While connected to a console, a number of commands may be performed through escape
@@ -20,11 +31,33 @@ keystroke will be interpreted as a command. The following commands are availabl
* `.`:
Exit the session and return to the command prompt
* `b`:
[send Break]
Send a break to the remote console when possible (some console plugins may not support this)
* `o`:
[reOpen]
Request confluent to disconnect and reconnect to console. For example if there is suspicion
that the console has gone inoperable, but would work if reconnected.
* `po`:
[Power Off]
Power off server immediately, without waiting for OS to shutdown
* `ps`:
[Power Shutdown]
Request OS shut down gracefully, and then power off
* `pb<ent>`:
[Power Boot]
Cause system to immediately boot, resetting or turning on as appropriate.
Hitting enter is required to execute the reboot rather than another pb sequence
* `pbs`:
[Power Boot Setup]
Request immediate boot ultimately landing in interactive firmware setup
* `pbn`:
[Power Boot Network]
Request immediate boot to network
* `r`:
[send Resize]
This queries the current terminal and sends stty commands to advertise the user termineal
size to the remote console
* `?`:
Get a list of supported commands
* `<enter>`:
Abandon entering an escape sequence command
* `<ent>`:
Hit enter to skip entering a command at the escape prompt.
+29
View File
@@ -0,0 +1,29 @@
nodedefine(8) -- Define new confluent nodes
===================================================================
## SYNOPSIS
`nodedefine <noderange> [nodeattribute1=value1> <nodeattribute2=value2> ...]`
## DESCRIPTION
`nodedefine` allows the definition of new nodes for the confluent management
system. It has the same syntax as `nodeattrib(8)`, and the commands differ in
that `nodeattrib(8)` will error if a node does not exist.
## EXAMPLES
* Define two racks of nodes, named r{rack}u{u}:
`# nodedefine r1u1-r2u4`
`r1u4: created`
`r1u1: created`
`r1u2: created`
`r1u3: created`
`r2u4: created`
`r2u3: created`
`r2u2: created`
`r2u1: created`
## SEE ALSO
noderange(5), nodeattribexpressions(8)
+144
View File
@@ -0,0 +1,144 @@
nodediscover(8) -- List or manage confluent node discovery
=========================================================
## SYNOPSIS
`nodediscover rescan`
`nodediscover [options] list`
`nodediscover [options] assign`
`nodediscover [options] rescan`
`nodediscover [options] clear`
## DESCRIPTION
**nodediscover** provides streamlined access to the confluent discovery data
and assignment. Nodes are detected through either an active scan (as occurs
at service startup and on request by nodediscover rescan) or through passive
detection (as a target comes online, it may attempt to register with the
network).
**nodediscover list** provides the currently known data in tabular format. The
data may be filtered by various parameters, as denoted in the options below.
**nodediscover assign** performs manual discovery, assigning an entry to a node
identity or, using `-i`, using a csv file to assign nodes all at once. For
example, a spreadsheet of serial numbers to desired node names could be used.
**nodediscover rescan** requests the server to do an active sweep for new
devices. Generally every effort is made to passively detect devices as they
become available (as they boot or are plugged in), however sometimes an active
scan is the best approach to catch something that appears to be missing.
**nodedsicover clear** requests the server forget about a selection of
detected device. It takes the same arguments as **nodediscover list**.
## CSV FORMAT
The CSV format used by nodediscover consists of one header describing the
columns followed by the data. The available columns are:
* node: The name desired for the node in confluent
* groups: A comma delimited list of groups to put the node into (using normal CSV escape rules for the commas)
* mac: The mac address of the node
* serial: The serial number of the node
* uuid: The uuid of the node
* bmc: The name or ip address that should be assigned to the BMC, regardless of current address
* bmc_gateway: IP address of gateway, if desired
* bmcuser: The desired username for the BMC to have as administrator
* bmcpass: The desired password for the BMC to require
Note that node is the only mandatory field. To identify the systems, one of
mac, serial, or uuid should be specified, it is pointless to provide more than
one of these columns. Other attributes if not provided may be defined through
nodeattrib or group inherited. It is possible to define nodes without ever
providing a BMC ip, in which case IPv6 will be used automatically if possible.
One example of a valid CSV file would be:
node,serial,bmc,bmcuser,bmcpass
n1,06DPMDF,172.30.204.1,admin,Passw0rd12
n2,J30002HG,172.30.204.2,admin,Passw0rd12
Which would use the serial number to assign the name and other three values to
the nodes.
## OPTIONS
* `-m MODEL`, `--model=MODEL`:
Operate with nodes matching the specified model number
* `-s SERIAL`, `--serial=SERIAL`:
Operate against the system matching the specified
serial number
* `-u UUID`, `--uuid=UUID`:
Operate against the system matching the specified UUID
* `-n NODE`, `--node=NODE`:
Operate with the given nodename
* `-e MAC`, `--ethaddr=MAC`:
Operate against the system with the specified MAC
address
* `-f FIELDS`, `--fields=FIELDS`:
Request a custom set of fields. The available fields are:
Node: The node name if a correlation has been identified
Model: The model number
Serial: The serial number
UUID: The UUID as it should appear in DMI
Type: Device type (e.g. lenovo-xcc, pxe-client, etc)
IP: The confirmed working IP addresses associated with the record
Mac: Mac address of the relevant network interface
Switch: The nearest detected switch to the entry
Port: Port of the switch that most closely connects to the network interface
Advertised IP: IP addresses that may not have been confirmed, but are advertised
* `-o ORDER`, `--order=ORDER`:
Order output by given field. Field names are the same as documented in the -f argument.
* `-t TYPE`, `--type=TYPE`:
Operate against the system of the specified type
* `-c`, `--csv`:
Use CSV formatted output
* `-i IMPORT.CSV`, `--import=IMPORT.CSV`:
Import bulk assignment data from given CSV file
* `-d STATE`, `--discoverystate=STATE`:
Indicate devices with a particular state. The states are listed below
* discovered: The device has been identified and has also had discovery
activities performed, including any relevant certificate
exchanges and deploying user and network configuration.
* identified: The device has been identified as to what node it is
supposed to be, however no active changes to the attributes
or device configuration has been performed. This is
generally discovery awaiting approval due to
discovery.policy specifying a strict security model.
* unidentified: A device has been sensed, but no node identity has been
established at all. It provides data that can be used
for nodediscover assign, as well as current IP addresses
that can be used for manual efforts as possible.
## EXAMPLES
* Listing all detected Lenovo IMMv2 systems on a local network:
`# nodediscover list -t lenovo-imm2`
` Node| Model| Serial| UUID| Mac Address| Type| Current IP Addresses`
`---------------|---------------|---------------|------------------------------------|-----------------|------------|------------------------------------------------`
` r2| 5463AC1| 06DPMDF|5f7133b8-c8cb-11e4-99a9-40f2e9b91018|40:f2:e9:b9:10:1d| lenovo-imm2| 172.30.204.1,fe80::42f2:e9ff:feb9:101d%eth1`
` | 7906AC1| 06PBX15|e98d483d-2759-11e1-8ffd-5cf3fc11249c|5c:f3:fc:11:24:9f| lenovo-imm2| 172.30.3.12,fe80::5ef3:fcff:fe11:249f%eth1`
` n1| 8737AC1| 23XXH41|14dd3ba6-5c38-11e1-931a-5cf3fc6e4680|5c:f3:fc:6e:13:e1| lenovo-imm2| 172.30.3.1,fe80::5ef3:fcff:fe6e:13e1%eth1`
` n7| 8737AC1| 23XXH32|79d2ce28-5cd5-11e1-8c86-5cf3fc6e46b0|5c:f3:fc:6e:13:f9| lenovo-imm2| 172.30.3.7,fe80::5ef3:fcff:fe6e:13f9%eth1`
` n8| 8737AC1| 23XXH49|551a8438-5cd5-11e1-8d6c-5cf3fc6e4708|5c:f3:fc:6e:14:25| lenovo-imm2| 172.30.3.8,fe80::5ef3:fcff:fe6e:1425%eth1`
` n3| 8737AC1| 23XXH30|1dd7f7b3-5da5-11e1-baf0-5cf3fc6e4738|5c:f3:fc:6e:14:3d| lenovo-imm2| 172.30.3.3,fe80::5ef3:fcff:fe6e:143d%eth1`
` n4| 8737AC1| 23XXH35|45b81dae-5d9b-11e1-8337-5cf3fc6e4858|5c:f3:fc:6e:14:cd| lenovo-imm2| 172.30.3.4,fe80::5ef3:fcff:fe6e:14cd%eth1`
` n11| 8737AC1| 23XXH12|31d90128-5c37-11e1-bdb7-5cf3fc6e4920|5c:f3:fc:6e:15:31| lenovo-imm2| 172.30.3.11,fe80::5ef3:fcff:fe6e:1531%eth1`
` n13| 8737AC1| 23XXH44|e23a138a-5cd3-11e1-8f3d-5cf3fc6e4950|5c:f3:fc:6e:15:49| lenovo-imm2| 172.30.3.13,fe80::5ef3:fcff:fe6e:1549%eth1`
` | 8737AC1| 23XXH29|5cd1216b-5c37-11e1-ba0c-5cf3fc6e49c8|5c:f3:fc:6e:15:85| lenovo-imm2| 172.30.3.9,fe80::5ef3:fcff:fe6e:1585%eth1`
` | 8737AC1| 23ZYT44|f4bf48ca-71f0-11e1-b274-5cf3fc6e4f10|5c:f3:fc:6e:18:29| lenovo-imm2| 172.30.3.10,fe80::5ef3:fcff:fe6e:1829%eth1`
` hpcedr| 7915AC1| 06DRHL5|a64e3014-d7e3-11e1-8d21-6cae8b1dff32|6c:ae:8b:1d:ff:36| lenovo-imm2| 172.30.254.250,fe80::6eae:8bff:fe1d:ff36%eth1`
` | 8737AC1| 06YRWC3|3af85a51-7efd-11e3-8599-000af7482e00|6c:ae:8b:32:cb:c5| lenovo-imm2| 172.30.3.6,fe80::6eae:8bff:fe32:cbc5%eth1`
` | 8737AC1| 06YRWB7|b230f62e-7efd-11e3-9773-000af7482980|6c:ae:8b:32:cd:01| lenovo-imm2| 172.30.3.5,fe80::6eae:8bff:fe32:cd01%eth1`
` | 8737AC1| 06YRWC7|09586005-7efe-11e3-9f03-000af7482df0|6c:ae:8b:32:cd:a5| lenovo-imm2| 172.30.3.2,fe80::6eae:8bff:fe32:cda5%eth1`
* Manually assign a single node according to serial number:
`[root@odin ~]# nodediscover assign -s 06PBX15 -n n12`
`Assigned: n12`
* Bulk execute discovery based on spreadsheet:
`[root@odin ~]# nodediscover assign -i import.csv`
`Defined r2`
`Discovered r2`
`Defined c1`
`Discovered c1`
@@ -0,0 +1,33 @@
nodeeventlog(8) -- Pull eventlog from confluent nodes
============================================================
## SYNOPSIS
`nodeeventlog <noderange>`
`nodeeventlog <noderange> [clear]`
## DESCRIPTION
`nodeeventlog` pulls and optionally clears the event log from the requested
noderange.
## EXAMPLES
* Pull the event log from n2 and n3:
`# nodeeventlog n2,n3`
`n2: 05/03/2017 11:44:25 Event Log Disabled - SEL Fullness - Log clear`
`n2: 05/03/2017 11:44:56 System Firmware - Progress - Unspecified`
`n3: 05/03/2017 11:44:39 Event Log Disabled - SEL Fullness - Log clear`
`n3: 05/03/2017 11:45:00 System Firmware - Progress - Unspecified`
`n3: 05/03/2017 11:47:22 System Firmware - Progress - Starting OS boot`
* Pull and clear the event log from n2 and n3:
`# nodeeventlog n2,n3 clear`
`n2: 05/03/2017 11:44:25 Event Log Disabled - SEL Fullness - Log clear`
`n2: 05/03/2017 11:44:56 System Firmware - Progress - Unspecified`
`n2: 05/03/2017 11:48:29 System Firmware - Progress - Starting OS boot`
`n3: 05/03/2017 11:44:39 Event Log Disabled - SEL Fullness - Log clear`
`n3: 05/03/2017 11:45:00 System Firmware - Progress - Unspecified`
`n3: 05/03/2017 11:47:22 System Firmware - Progress - Starting OS boot`
`# nodeeventlog n2,n3`
`n2: 05/03/2017 11:48:48 Event Log Disabled - SEL Fullness - Log clear`
`n3: 05/03/2017 11:48:52 Event Log Disabled - SEL Fullness - Log clear`
@@ -0,0 +1,47 @@
nodefirmware(8) -- Report firmware information on confluent nodes
=================================================================
## SYNOPSIS
`nodefirmware <noderange>`
`nodefirmware <noderange> list|<components>|core`
`nodefirmware <noderange> update [--backup] <filename>`
## DESCRIPTION
`nodefirmware` reports and updates various firmware on nodes. By default it
will retrieve all firmware, but can be directed to fetch specific firmware by
calling out the name of the firmware (e.g. uefi or xcc) or request reading only
core firmware firmware by using the word 'core', which is generally a quicker
operation. Different hardwaremanagement.method indicated plugins may have
different capabilities available. For example, the 'core' distinction may
not be relevant to redfish. Additionally, the Lenovo XCC makes certain
information available over IPMI that is not otherwise available (for example
the FPGA version where applicable).
In the update form, it accepts a single file and attempts to update it using
the out of band facilities. Firmware updates can end in one of three states:
* `error`: The attempted update encountered an error that prevented successful install. Nodes experiencing this state will be reported at the end and more detail on the error will be given
* `pending`: The firmware update process has completed, but the firmware will not be active until the relevant component next resets. Generally speaking, for UEFI update the system will need a reboot, and for BMC updates, the `nodebmcreset` command will begin the process to activate the firmware.
* `complete`: The firmware update process has completed and activation has proceeded. Note that while the activation process has commenced, the component may still be in the process of rebooting when nodefirmware exits.
## EXAMPLES
* Pull firmware from a node:
`# nodefirmware r1`
`r1: IMM: 3.70 (TCOO26H 2016-11-29T05:09:51)`
`r1: IMM Backup: 1.71 (TCOO10D 2015-04-17T00:00:00)`
`r1: IMM Trusted Image: TCOO26H`
`r1: UEFI: 2.31 (TCE128I 2016-12-13T00:00:00)`
`r1: UEFI Backup: 2.20 (TCE126O)`
`r1: FPGA: 3.2.0`
`r1: Broadcom NetXtreme Gigabit Ethernet Controller Bootcode: 1.38`
`r1: Broadcom NetXtreme Gigabit Ethernet Controller MBA: 16.8.0`
`r1: Broadcom NetXtreme Gigabit Ethernet Controller Firmware Package: 0.0.0a`
`r1: ServeRAID M1215 MegaRAID Controller Firmware: 24.12.0-0038 (2016-10-20T00:00:00)`
`r1: ServeRAID M1215 Disk 28 MBF2600RC: SB2C`
`r1: ServeRAID M1215 Disk 29 MBF2600RC: SB2C`
`r1: ServeRAID M5210 Disk 0 MBF2600RC: SB2C`
`r1: ServeRAID M5210 Disk 1 MBF2600RC: SB2C`
`r1: ServeRAID M5210 Disk 2 MBF2600RC: SB2C`
@@ -0,0 +1,43 @@
nodegroupattrib(8) -- List or change confluent nodegroup attributes
===================================================================
## SYNOPSIS
`nodegroupattrib <group> [ current | all ]`
`nodegroupattrib <group> [<nodeattribute>...]`
`nodegroupattrib <group> [<nodeattribute1=value1> <nodeattribute2=value2> ...]`
`nodegroupattrib <group> [-c] [<nodeattribute1> <nodeattribute2=value2> ...]`
`nodeattrib -p <noderange> <nodeattribute1> <nodeattribute2> ...`
## DESCRIPTION
`nodegroupattrip` queries the confluent server to get information about nodes.
In the simplest form, it simply takes the given group and lists the attributes of that group.
Contrasted with nodeattrib(8), settings managed by nodegroupattrib will be added
and removed from a node as it is added or removed from a group. If an attribute
is set using nodeattrib(8) against a noderange(5) that happens to be a group name,
nodeattrib(8) individually sets attributes directly on each individual node that is
currently a member of that group. Removing group membership or adding a new
node after using the nodeattrib(8) command will not have attributes change automatically.
It's easiest to see by using the `nodeattrib <noderange> -b` to understand how
the attributes are set on the node versus a group to which a node belongs.
## OPTIONS
* `-c`, `--clear`:
Clear specified nodeattributes.
## EXAMPLES
* Show attributes of a group called `demogrp`:
`# nodegroupattrib demogrp`
`demogrp: hardwaremanagement.manager: (will derive from expression 10.30.{n0/255}.{n0%255})`
`demogrp: nodes: n12,n13,n10,n11,n9,n1,n2,n3,n4`
* Set location.u to be the remainder of first number in node name when divided by 42:
`# nodegroupattrib demogrp location.u={n1%42}`
## SEE ALSO
nodeattrib(8), nodeattribexpressions(5)
@@ -0,0 +1,24 @@
nodegroupdefine(8) -- Define new confluent node group
===================================================================
## SYNOPSIS
`nodegroupdefine <groupname> [nodeattribute1=value1> <nodeattribute2=value2> ...]`
## DESCRIPTION
`nodegroupdefine` allows the definition of a new nodegroup for the confluent management
service. It may only define a single group name at a time.
It has the same syntax as `nodegroupattrib(8)`, and the commands differ in
that `nodegroupattrib(8)` will error if a node group does not exist.
## EXAMPLES
* Create a group called `compute`:
`# nodegroupdefine compute`
`compute: created`
## SEE ALSO
nodeattribexpressions(8), nodegroupattrib(8), nodegroupremove(8)
@@ -0,0 +1,14 @@
nodegrouplist(8) -- List the defined confluent nodegroups
===================================================================
## SYNOPSIS
`nodegrouplist`
## DESCRIPTION
`nodegrouplist` lists the currently defined groups in confluent.
## SEE ALSO
nodeattrib(8), nodeattribexpressions(5), nodegroupattrib(8)
@@ -0,0 +1,18 @@
nodegroupremove(8) -- Remove a nodegroup from the confluent database
====================================================================
## SYNOPSIS
`nodegroupremove <noderange>`
## DESCRIPTION
`nodegroupremove` simply removes the given single nodegroup from the confluent database.
## EXAMPLES
* Remove group called testgroup
`# nodegroupremove testgroup`
`testgroup: deleted`
+22
View File
@@ -0,0 +1,22 @@
nodehealth(8) -- Show health summary of confluent nodes
========================================================
## SYNOPSIS
`nodehealth <noderange>`
## DESCRIPTION
`nodehealth` reports the current health assessment of a confluent node. It
will report either `ok`, `warning`, `critical`, or `failed`, along with
a string explaining the reason for any result other than `ok`.
## EXAMPLES
* Pull health summary of 5 nodes:
`# nodehealth n1-n4,r1`
`n1: critical (Mezz Exp 2 Fault:Critical)`
`n3: ok`
`n2: ok`
`r1: ok`
`n4: ok`
@@ -0,0 +1,32 @@
nodeidentify(8) -- Control the identify LED of confluent nodes
=========================================================
## SYNOPSIS
`nodidentify <noderange> [on|off|blink]`
## DESCRIPTION
`nodeidentify` allows you to turn on or off the location LED of conflueunt nodes,
making it easier to determine the physical location of the nodes. The following
options are supported:
* `on`: Turn on the identify LED
* `off`: Turn off the identify LED
* `blink`: Set the identify LED to blink (when supported by the system)
## EXAMPLES:
* Turn on the identify LED on nodes n1 through n4:
`# nodeidentify n1-n4 on`
`n1: on`
`n2: on`
`n3: on`
`n4: on`
* Turn off the identify LED on nodes n1 thorugh n4:
`# nodeidentify n1-n4 off`
`n1: off`
`n2: off`
`n4: off`
`n3: off`
+121
View File
@@ -0,0 +1,121 @@
nodeinventory(8) -- Get hardware inventory of confluent node
===============================================================
## SYNOPSIS
`nodeinventory <noderange> [serial|model|uuid|mac]`
## DESCRIPTION
`nodeinventory` pulls information about hardware of a node. This includes
information such as adapters, serial numbers, processors, and memory modules,
as supported by the platforms hardware management implementation. It accepts
arguments such as serial or model or others as listed above to filter
output to specific data.
## EXAMPLES
* Pulling inventory of a node named r1:
`# nodeinventory r1`
`r1: System MAC Address 1: 40:f2:e9:af:45:a0`
`r1: System MAC Address 2: 40:f2:e9:af:45:a1`
`r1: System MAC Address 3: 40:f2:e9:af:45:a2`
`r1: System MAC Address 4: 40:f2:e9:af:45:a3`
`r1: System Board manufacturer: IBM`
`r1: System Product name: System x3650 M5`
`r1: System Device ID: 32`
`r1: System Revision: 9`
`r1: System Product ID: 323`
`r1: System Board model: 00KG915`
`r1: System Device Revision: 0`
`r1: System Serial Number: E2K4831`
`r1: System Board manufacture date: 2014-10-20T12:00`
`r1: System Board serial number: Y010UF4AL0B5`
`r1: System Manufacturer: IBM`
`r1: System FRU Number: 00FK639`
`r1: System Board product name: System Board`
`r1: System Model: 5462AC1`
`r1: System UUID: 1B29CE46-765E-31A3-A3B9-B5FB934F15AB`
`r1: System Hardware Version: 0x0000`
`r1: System Manufacturer ID: 20301`
`r1: System Chassis serial number: E2K4831`
`r1: System Asset Number: `
`r1: System Chassis type: Other`
`r1: Power Supply 1 Board model: 94Y8136`
`r1: Power Supply 1 Board manufacturer: EMER`
`r1: Power Supply 1 FRU Number: 94Y8137`
`r1: Power Supply 1 Board product name: IBM Designed Device`
`r1: Power Supply 1 Board manufacture date: 2014-11-08T00:00`
`r1: Power Supply 1 Board serial number: K13814B88ED`
`r1: Power Supply 1 Revision: 49`
`r1: Power Supply 2: Not Present`
`r1: DASD Backplane 1 Board model: 00JY139`
`r1: DASD Backplane 1 Board manufacturer: WIST`
`r1: DASD Backplane 1 FRU Number: 00FJ756`
`r1: DASD Backplane 1 Board product name: IBM Designed Device`
`r1: DASD Backplane 1 Board manufacture date: 2014-08-28T00:00`
`r1: DASD Backplane 1 Board serial number: Y011UF48W02U`
`r1: DASD Backplane 1 Revision: 0`
`r1: DASD Backplane 2: Not Present`
`r1: DASD Backplane 3: Not Present`
`r1: DASD Backplane 4: Not Present`
`r1: DASD Backplane 5 Board model: 00YJ530`
`r1: DASD Backplane 5 Board manufacturer: WIST`
`r1: DASD Backplane 5 FRU Number: 00AL953`
`r1: DASD Backplane 5 Board product name: IBM Designed Device`
`r1: DASD Backplane 5 Board manufacture date: 2016-02-04T00:00`
`r1: DASD Backplane 5 Board serial number: Y010UF624024`
`r1: DASD Backplane 5 Revision: 0`
`r1: DASD Backplane 6: Not Present`
`r1: CPU 1 Hardware Version: Intel(R) Xeon(R) CPU E5-2640 v3 @ 2.60GHz`
`r1: CPU 1 Asset Number: Unknown`
`r1: CPU 1 Manufacturer: Intel(R) Corporation`
`r1: CPU 2: Not Present`
`r1: ML2 Card: Not Present`
`r1: DIMM 1: Not Present`
`r1: DIMM 2: Not Present`
`r1: DIMM 3: Not Present`
`r1: DIMM 4: Not Present`
`r1: DIMM 5: Not Present`
`r1: DIMM 6: Not Present`
`r1: DIMM 7: Not Present`
`r1: DIMM 8: Not Present`
`r1: DIMM 9: Not Present`
`r1: DIMM 10: Not Present`
`r1: DIMM 11: Not Present`
`r1: DIMM 12: Not Present`
`r1: DIMM 13: Not Present`
`r1: DIMM 14: Not Present`
`r1: DIMM 15: Not Present`
`r1: DIMM 16: Not Present`
`r1: DIMM 17: Not Present`
`r1: DIMM 18: Not Present`
`r1: DIMM 19: Not Present`
`r1: DIMM 20: Not Present`
`r1: DIMM 21: Not Present`
`r1: DIMM 22: Not Present`
`r1: DIMM 23: Not Present`
`r1: DIMM 24: Not Present`
`r1: X8 PCI 1: Not Present`
`r1: X8 PCI 2: Not Present`
`r1: X8 PCI 6: Not Present`
`r1: X8 PCI 7: Not Present`
`r1: Broadcom NetXtreme Gigabit Ethernet Controller MAC Address 1: 40:f2:e9:af:45:a0`
`r1: Broadcom NetXtreme Gigabit Ethernet Controller MAC Address 2: 40:f2:e9:af:45:a1`
`r1: Broadcom NetXtreme Gigabit Ethernet Controller MAC Address 3: 40:f2:e9:af:45:a2`
`r1: Broadcom NetXtreme Gigabit Ethernet Controller MAC Address 4: 40:f2:e9:af:45:a3`
`r1: Broadcom NetXtreme Gigabit Ethernet Controller PCI slot: 1b:00`
`r1: Broadcom NetXtreme Gigabit Ethernet Controller location: Onboard`
* Reporting just the mac addresses of a node named r2:
`# nodeinventory r2 mac`
`r2: System MAC Address 1: 40:f2:e9:b9:10:18`
`r2: System MAC Address 2: 40:f2:e9:b9:10:19`
`r2: System MAC Address 3: 40:f2:e9:b9:10:1a`
`r2: System MAC Address 4: 40:f2:e9:b9:10:1b`
* Getting the model number and serial number of a node named s2:
`# nodeinventory stark2 serial model`
`s2: System Product name: LENOVO THINKSYSTEM SD530 SERVER`
`s2: System Serial Number: DEV0000002`
`s2: System Model: 7X2104Z028`
+17
View File
@@ -0,0 +1,17 @@
nodelicense(8) -- Manage license keys on BMC
=================================================================
## SYNOPSIS
`nodelicense <noderange> [list|install <filename>|delete <license>|save <directory>]`
## DESCRIPTION
`nodelicense` manages license keys on supported BMCs. Without an argument, the command
lists currently installed license. Using `delete` will remove the specified license name
from th eBMC. The `save` subcommand will take the passed directory (which may be in the form
of /path/to/{node}/ to have the node name substituted for each node) and back up installed licenses
to that directory. The `install` command will take the specified filename and install. The filename
argument may be of the form xcc_fod_0034_7X21{id.serial}.key to have the serial number substituted
to allow unique licenses to be specified in a single command.
+6 -4
View File
@@ -1,10 +1,10 @@
nodelist(1) -- List confluent nodes and their attributes
nodelist(8) -- List confluent nodes and their attributes
=========================================================
## SYNOPSIS
`nodelist` `noderange`
`nodelist` `noderange` [-b] [<nodeattribute>...]
`nodelist <noderange>`
`nodelist <noderange> [-b] <nodeattribute>...`
## DESCRIPTION
@@ -17,6 +17,9 @@ displayed. If `-b` is specified, it will also display information on
how inherited and expression based attributes are defined. There is more
information on node attributes in nodeattributes(5) man page.
Attributes may be specified by wildcard, for example `net.*switch` will report
all attributes that begin with `net.` and end with `switch`.
## OPTIONS
* `-b`, `--blame`:
@@ -45,4 +48,3 @@ information on node attributes in nodeattributes(5) man page.
`n2: hardwaremanagement.method: ipmi (inherited from group everything)`
`n2: hardwaremanagement.switch: r8e1`
`n2: hardwaremanagement.switchport: 2`
+57
View File
@@ -0,0 +1,57 @@
nodemedia(8) -- Manage server remote media
=========================================================
## SYNOPSIS
`nodemedia <noderange> [attach|detachall|list|upload] [options] <media>`
## DESCRIPTION
**nodemedia** manages the remote media functionality of supported BMCs.
`list` shows all the current remote media the BMCs of the noderange are
providing to the host platform. The string (insecure) is appended to URLs that
are mounted in an insecure fashion. http is insecure, and https is also
insecure when no meaningful certificate validation is performed. Currently
there is no action that can change this, and this is purely informational. A
future version of software may provide a means to increase security of attached
remote media. If no media is mounted, this will provide no output, error
conditions will result in output to standard error.
`detachall` removes all the currently provided media to the host. This unlinks
remote media from urls and deletes uploaded media from the BMC.
`upload` takes the given media image and uploads it to the BMC. This causes
the remote media to reside internally to the system without having to go
to the network after the upload. This is more constrained, for example the
Lenovo xClarity Controller has a limit of 50 megabytes, but it has zero ongoing
load on the media source.
`attach` takes a URL to a remote media as an argument, and has the given
BMCs map a virtual USB device to that url. Content is loaded on demand, and
as such that URL is referenced potentially once for every IO operation that
the host platform attempts.
## OPTIONS
* `-c`:
Specify the maximum number of instances to run concurrently.
## EXAMPLES
* Listing currently mounted media:
`# nodemedia s1-s4 list`
`s1: boot.img`
`s2: boot.img`
`s4: boot.img`
* Uploading a small boot image to the BMC:
`# nodemedia s1-s4 upload boot.img`
`s1:complete: 100% s2:complete: 100% s3:complete: 100% s4:complete: 100%`
`s1: boot.img`
`s4: boot.img`
`s2: boot.img`
* Attaching a larger ISO for on-demand access:
`# nodemedia s1,s4 attach http://172.30.0.6/install/rhel74.iso`
`s4: http://172.30.0.6/install/rhel74.iso (insecure)`
`s1: http://172.30.0.6/install/rhel74.iso (insecure)`
+48
View File
@@ -0,0 +1,48 @@
nodepower(8) -- Check or change power state of confluent nodes
=========================================================
## SYNOPSIS
`nodepower <noderange>`
`nodepower <noderange> [-p] [on|off|boot|shutdown|reset|status]`
## DESCRIPTION
**nodepower** with only a noderange will retrieve current power state of nodes
through confluent. When given an additional argument, it will request a change
to the power state of the nodes. The following arguments are recognized:
* `on`: Turn on the specified noderange. Nothing will happen to nodes of
the noderange that are already on.
* `off`: Immediately turn off the specified noderange, without waiting for OS
to shutdown. Nothing will happen to nodes of the noderange that are already on.
* `boot`: Immediately boot a system. This will power on nodes of the noderange
that are off, and reset nodes of the noderange that are on. The previous state
will be reflected in the output.
* `shutdown`: Request the OS gracefully shut down. Nothing will happen for
nodes that are off, and nodes will not shutdown if the OS fails to gracefully
respond.
* `reset`: Request immediate reset of nodes of the noderange. Nodes that are
off will not react to this request.
* `status`: Behave identically to having no argument passed at all.
## OPTIONS
* `-p`, '--showprevious':
Show previous power state for all directives that may change power state.
## EXAMPLES
* Get power state of nodes n1 through n4:
`# nodepower n1-n4`
`n1: on`
`n2: on`
`n3: on`
`n4: off`
* Forcing a reboot of nodes n1-n4:
`# nodepower n1-n4 boot`
`n3: on->reset`
`n1: on->reset`
`n2: on->reset`
`n4: off->on`
+60
View File
@@ -0,0 +1,60 @@
noderange(5) -- Indicate a target set of nodes in confluent
=========================================================
## SYNOPSIS
`<noderange>`
## DESCRIPTION
<noderange> is a syntax that can be used in most Confluent commands to conveniently specify a list of nodes. The result is that the command will be applied to a range of nodes, often in parallel.
## EXAMPLES:
The simplest noderange is a single node name:
`n1`
Nodes and groups may be used interchangeably. The following may be used in any context where n1 would be accepted as a noderange:
`rack1`
Commonly, there is a desire to target a range of elements. There are a few identically behaving syntaxes for the purpose.
`n1:n20`
`n1-n20`
`n[1-20]`
Note that numbers may be zero padded or not, it will automatically detect the padding amount and adjust members of the range accordingly. Ranges also can understand multiple numeric values changing:
`r[1-3]u[01-10]`
`r1u01-r3u10`
Ranges can also be applied to group names, and all above syntaxes are compatible:
`rack1-rack10`
`rack[1-10]`
Also, regular expressions may be used to indicate nodes with names matching certain patterns:
`~r1u..`
The other major noderange primitive is indicating nodes by some attribute value:
`location.rack=7`
The attribute name may use a wildcard:
`net.*switch=switch1`
Commas can be used to indicate multiple nodes, and can mix and match any of the above primitives. The following can be a valid single noderange, combining any and all members of each comma separated component
`n1,n2,rack1,storage,location.rack=9,~s1..,n20-n30`
Exclusions can be done by prepending a '-' before a portion of a noderange:
`rack1,-n2`
`compute,-rack1`
`compute,-location.row=12`
To indicate nodes that match multiple selections at once (set intersection), the @ symbol may be used:
`compute@rack1`
`location.rack=10@compute`
For complex expressions, () may be used to indicate order of expanding the noderange to be explicit
`rack1,-(console.logging=full@compute)`
Noderange syntax can also indicate 'pagination', or separating the nodes into well defined chunks. > is used to indicate how many nodes to display at a time, and < is used to indicate how many nodes to skip into a noderange:
`rack1>3<6`
The above would show the seventh through ninth nodes of the rack1 group. Like all other noderange operations, this may be combined with any of the above, but must appear as the very last operation. Ordering is done with a natural sort.
+25
View File
@@ -0,0 +1,25 @@
noderemove(8) -- Remove nodes from the confluent management service
===================================================================
## SYNOPSIS
`noderemove <noderange>`
## DESCRIPTION
`noderemove` simply removes the given noderange from the confluent database.
## EXAMPLES
* Remove two racks each with 4 nodes:
`# noderemove r1u1-r2u4`
`r1u4: deleted`
`r1u1: deleted`
`r1u2: deleted`
`r1u3: deleted`
`r2u4: deleted`
`r2u3: deleted`
`r2u2: deleted`
`r2u1: deleted`
+19
View File
@@ -0,0 +1,19 @@
nodereseat(8) -- Request a reseat of a node
============================================
## SYNOPSIS
`nodereseat <noderange>`
## DESCRIPTION
`nodereseat` requests the enclosure manager of the current node to reseat that
node's slot. This should be equivalent to removing the system entirely from
the chassis and putting it back in, but without actually having to do so.
## EXAMPLES
* Reseating the node `s1`:
`# nodereseat s1`
`s1: Reseat successful`
+57
View File
@@ -0,0 +1,57 @@
noderun(8) -- Run arbitrary commands per node in a noderange
=============================================================
## SYNOPSIS
`noderun <noderange> <command string>`
## DESCRIPTION
`noderun` will take a given command and execute it in parallel once per node
in the specified noderange. Attribute expressions as documented in
nodeattribexpressions(5) are expanded prior to execution of the command. For
noderun, the commands are locally executed. To execute commands on the nodes
themselves, see nodeshell(8).
## EXAMPLES
* Run ping against nodes n1 through n4:
`# noderun n1-n4 ping -c 1 {nodename}`
`n3: PING n3 (172.30.2.3) 56(84) bytes of data.`
`n3: 64 bytes from n3 (172.30.2.3): icmp_seq=1 ttl=64 time=0.387 ms`
`n3: `
`n3: --- n3 ping statistics ---`
`n3: 1 packets transmitted, 1 received, 0% packet loss, time 0ms`
`n3: rtt min/avg/max/mdev = 0.387/0.387/0.387/0.000 ms`
`n4: PING n4 (172.30.2.4) 56(84) bytes of data.`
`n4: 64 bytes from n4 (172.30.2.4): icmp_seq=1 ttl=64 time=0.325 ms`
`n4: `
`n4: --- n4 ping statistics ---`
`n4: 1 packets transmitted, 1 received, 0% packet loss, time 0ms`
`n4: rtt min/avg/max/mdev = 0.325/0.325/0.325/0.000 ms`
`n2: PING n2 (172.30.2.2) 56(84) bytes of data.`
`n2: From odin (172.30.0.6) icmp_seq=1 Destination Host Unreachable`
`n2: `
`n2: --- n2 ping statistics ---`
`n2: 1 packets transmitted, 0 received, +1 errors, 100% packet loss, time 3000ms`
`n2: `
`n1: PING n1 (172.30.2.1) 56(84) bytes of data.`
`n1: `
`n1: --- n1 ping statistics ---`
`n1: 1 packets transmitted, 0 received, 100% packet loss, time 10000ms`
`n1: `
* Run an ipmitool raw command against the management controllers of n1 through n4:
`# noderun n1-n4 ipmitool -I lanplus -U USERID -E -H {hardwaremanagement.manager} raw 0 1`
`n3: 01 10 00`
`n1: 01 10 00`
`n4: 01 10 00`
`n2: 01 10 00`
* If wanting to use literal {} in the command, they must be escaped by doubling:
`# noderun n1-n4 "echo {node} | awk '{{print $1}}'"`
## SEE ALSO
nodeshell(8)
+2 -2
View File
@@ -1,9 +1,9 @@
nodesensors(1) --- Retrieve telemetry for sensors of confluent nodes
nodesensors(8) --- Retrieve telemetry for sensors of confluent nodes
====================================================================
## SYNOPSIS
`nodesensors` `noderange` [-c] [-i <interval>] [-n <samplecount>] [<sensor name or category>...]
`nodesensors <noderange> [-c] [-i <interval>] [-n <samplecount>] [<sensor name or category>...]`
## DESCRIPTION
+72
View File
@@ -0,0 +1,72 @@
nodesetboot(8) -- Check or set next boot device for noderange
====================================================
## SYNOPSIS
`nodesetboot <noderange>`
`nodesetboot [options] <noderange> [default|cd|network|setup|hd]`
## DESCRIPTION
Requests that the next boot occur from the specified device. Unless otherwise
specified, this is a one time boot option, and does not change the normal boot
behavior of the system. This is useful for taking a system that normally boots
to the hard drive and startking a network install, or to go into the firmware
setup menu without having to hit a keystroke at the correct time on the console.
Generally, it's a bit more convenient and direct to use the nodeboot(8) command,
which will follow up the boot device with an immediate power directive to take
effect. The `nodesetboot` command is still useful, particularly if you want
to use `nodesetboot <noderange> setup` and then initiate a reboot from within
the operating system with ssh or similar rather than using the remote hardware
control.
## OPTIONS
* `-b`, `--bios`:
For a system that supports both BIOS and UEFI style boot, request BIOS style
boot if supported (some platforms will UEFI boot with this flag anyway).
* `-p`, `--persist`:
For a system that supports it, mark the boot override to persist rather than
be a one time change. Many systems do not support this functionality.
* `-u`, `--uefi`:
This flag does nothing, it is for command compatibility with xCAT's rsetboot
* `default`:
Request a normal default boot with no particular device override
* `cd`:
Request boot from media. Note that this can include physical CD,
remote media mounted as CD/DVD, and detachable hard disks drives such as usb
key devices.
* `network`:
Request boot to network
* `setup`:
Request to enter the firmware configuration menu (e.g. F1 setup) on next boot.
* `hd`:
Boot straight to hard disk drive
## EXAMPLES
* Set next boot to setup for four nodes:
`# nodesetboot n1-n4 setup`
`n1: setup`
`n3: setup`
`n2: setup`
`n4: setup`
* Check boot override settings on four nodes:
`# nodesetboot n1-n4`
`n1: setup`
`n2: setup`
`n3: setup`
`n4: setup`
## SEE ALSO
nodeboot(8)
+37
View File
@@ -0,0 +1,37 @@
nodeshell(8) -- Execute command on many nodes in a noderange through ssh
=========================================================================
## SYNOPSIS
`nodeshell <noderange> [options] <command to execute on each node>`
## DESCRIPTION
Allows execution of a command on many nodes in parallel. Like noderun(8), it
accepts and interpolates confluent attribute expressions as documented in
nodeattribexpressions(5). `nodeshell` provides stdout as stdout and stderr
as stderr, unlike psh which combines all stdout and stderr into stdout.
## OPTIONS
* `-c`:
Specify the maximum number of instances to run concurrently.
## EXAMPLES
* Running `echo hi` on for nodes:
`# nodeshell n1-n4 echo hi`
`n1: hi`
`n2: hi`
`n3: hi`
`n4: hi`
* Setting a new static ip address temporarily on secondary interface of four nodes:
`# nodeshell n1-n4 ifconfig eth1 172.30.93.{n1}`
* If wanting to use literal {} in the command, they must be escaped by doubling:
`# nodeshell n1-n4 "ps | awk '{{print $1}}'"`
## SEE ALSO
noderun(8)
+65
View File
@@ -0,0 +1,65 @@
nodestorage(8) -- Examine/Modify storage configuration of a node
============================================
## SYNOPSIS
`nodestorage <noderange> [show|create|delete] [options]`
## DESCRIPTION
`nodestorage` provides access to the remote storage configuration of
the noderange.
## OPTIONS
* `-r` **RAIDLEVEL**, `--raidlevel`=**RAIDLEVEL**:
RAID level to use when creating an array
* `-d` **DISKS**, `--disks`=**DISKS**:
Comma separated list of disks to use, or the word "rest" to
indicate use of all available disks
* `-s` **SIZE**, `--size`=**SIZE**:
Comma separated list of sizes to use when creating
volumes. The sizes may be absolute size (e.g. 16gb),
percentage (10%) or the word "rest" to use remaining
capacity, default behavior is to use all capacity to
make a volume
* `-n` **NAME**, `--name`=**NAME**:
Comma separated list of names to use when naming
volumes, or selecting a volume for delete. Default
behavior is to use implementation provided default
## EXAMPLES
* Deleting the volume `somedata`:
`$ nodestorage d5 delete somedata`
`Deleted: somedata`
* Creating a raid5 of 4 disks and a volume named `somedata`:
`$ nodestorage d5 create -r 5 -d drive0,drive_1,drive_2,drive_3 -n somedata`
`d5: Volume somedata: Size: 1.905 TB`
`d5: Volume somedata: State: Optimal`
`d5: Volume somedata: Array 1-2`
* Showing current storage configuration of `d3`:
`$ nodestorage d3`
`d3: Disk m.2-0 Description: 128GB M.2 SATA SSD`
`d3: Disk m.2-0 State: online`
`d3: Disk m.2-0 FRU: 00LF428`
`d3: Disk m.2-0 Serial Number: H6B80054`
`d3: Disk m.2-0 Array: 0-0`
`d3: Disk m.2-1 Description: 128GB M.2 SATA SSD`
`d3: Disk m.2-1 State: online`
`d3: Disk m.2-1 FRU: 00LF428`
`d3: Disk m.2-1 Serial Number: H6B80059`
`d3: Disk m.2-1 Array: 0-0`
`d3: Array 0-0 Available Capacity: 0.000 MB`
`d3: Array 0-0 Total Capacity: 131.072 GB`
`d3: Array 0-0 RAID: RAID 1`
`d3: Array 0-0 Disks: m.2-0,m.2-1`
`d3: Array 0-0 Volumes: new_vd`
`d3: Volume new_vd: Size: 122.040 GB`
`d3: Volume new_vd: State: Optimal`
`d3: Volume new_vd: Array 0-0`
+32
View File
@@ -0,0 +1,32 @@
nodesupport(8) -- Utilities for interacting with vendor support
=================================================================
## SYNOPSIS
`nodesupport <noderange> servicedata <directory or filename>`
## DESCRIPTION
`nodesupport` provides capabilities associated with interacting with support.
Currently it only has the `servicedata` subcommand. `servicedata` takes
an argument that is either a directory name (that can be used for a single node
or multiple nodes) or a file name (only to be used with single node noderange).
Note that the file will be downloaded to the confluent server that actually
connects to the managed system, so it will download to the remote system if running
remotely and will download to the collective.manager indicated system if
running in collective mode.
Note that due to vendor filename requirements, any filename may have vendor
specific suffixes added to any file produced.
## EXAMPLES
* Download support data from a single node to a specific filename
`# nodesupport d1 servicedata svcdata.out`
`d1:initializing: 15%`
* Download support data from multiple nodes to a directory
`# nodesupport d1-d4 servicedata service/`
`d1:initializing: 0% d2:initializing: 0% d3:initializing: 0% d4:initializing: 0%`
`# ls service/`
`d1.svcdata d2.svcdata d3.svcdata d4.svcdata`
+10
View File
@@ -0,0 +1,10 @@
#!/bin/sh
cd `dirname $0`/doc/man
mkdir -p ../../man/man1
mkdir -p ../../man/man5
mkdir -p ../../man/man8
ronn -r *.ronn
mv *.1 ../../man/man1/
mv *.5 ../../man/man5/
mv *.8 ../../man/man8/
@@ -0,0 +1,35 @@
#!/usr/bin/python2
# This is a sample python script for going through all observed mac addresses
# and assuming they are BMC related and printing nodeattrib commands
# for each node to access the bmc using the interface specified on the command
# line
# Not necessarily as useful if there may be mistakes in the
# net.switch/net.switchport attributes, but a handy utility in a pinch when
# you really know
import confluent.client as cl
import socket
import struct
c = cl.Command()
macs = []
interface = sys.argv[1]
for mac in c.read('/networking/macs/by-mac/'):
macs.append(mac['item']['href'])
for mac in macs:
macinfo = list(c.read('/networking/macs/by-mac/{0}'.format(mac)))[0]
if 'possiblenode' in macinfo and macinfo['possiblenode']:
if macinfo['macsonport'] > 1:
print('#Ambiguous set of macs on port for ' + macinfo[
'possiblenode'])
prefix = int(mac.replace('-', '')[:6], 16) ^ 0b100000000000000000
prefix = prefix << 8
prefix |= 0xff
suffix = int(mac.replace('-', '')[6:], 16)
suffix |= 0xfe000000
rawn = struct.pack('!QLL', 0xfe80000000000000, prefix, suffix)
bmc = socket.inet_ntop(socket.AF_INET6, rawn)
print('nodeattrib {0} bmc={1}%{2}'.format(macinfo['possiblenode'],
bmc, interface))
+9 -2
View File
@@ -1,7 +1,14 @@
from setuptools import setup
import os
scriptlist = ['bin/{0}'.format(d) for d in os.listdir('bin/')]
data_files = [('/etc/profile.d', ['confluent_env.sh', 'confluent_env.csh'])]
try:
scriptlist = ['bin/{0}'.format(d) for d in os.listdir('bin/')]
data_files.append(('/opt/confluent/share/man/man1', ['man/man1/' + x for x in os.listdir('man/man1')]))
data_files.append(('/opt/confluent/share/man/man5', ['man/man5/' + x for x in os.listdir('man/man5')]))
data_files.append(('/opt/confluent/share/man/man8', ['man/man8/' + x for x in os.listdir('man/man8')]))
except OSError:
pass
setup(
name='confluent_client',
@@ -11,5 +18,5 @@ setup(
url='http://xcat.sf.net/',
packages=['confluent'],
scripts=scriptlist,
data_files=[('/etc/profile.d', ['confluent_env.sh','confluent_env.csh'])],
data_files=data_files,
)
+2 -2
View File
@@ -22,10 +22,10 @@ This provides the modules common for both client and server
%setup -n %{name}-%{version} -n %{name}-%{version}
%build
python setup.py build
python2 setup.py build
%install
python setup.py install --single-version-externally-managed -O1 --root=$RPM_BUILD_ROOT --record=INSTALLED_FILES --install-purelib=/opt/confluent/lib/python --install-scripts=/opt/confluent/bin
python2 setup.py install --single-version-externally-managed -O1 --root=$RPM_BUILD_ROOT --record=INSTALLED_FILES --install-purelib=/opt/confluent/lib/python --install-scripts=/opt/confluent/bin
%clean
rm -rf $RPM_BUILD_ROOT
-17
View File
@@ -1,17 +0,0 @@
[metadata]
name = confluent_common
summary = Confluent Common Libraries
description-file =
README.txt
author = Jarrod Johnson
author-email = jjohnson2@lenovo.com
home-page = http://xcat.sf.net/
classifier =
Intended Audience :: Information Technology
Intended Audience :: System Administrators
License :: OSI Approved :: Apache Software License
Operating System :: POSIX :: Linux
Programming Language :: Python :: 2.6
Programming Language :: Python :: 2.7
[files]
+2
View File
@@ -1,2 +1,4 @@
include pam/*
include sysvinit/*
include systemd/*
include sysctl/*
+139
View File
@@ -0,0 +1,139 @@
#!/usr/bin/python2
import argparse
import errno
import os
import socket
import subprocess
import sys
path = os.path.dirname(os.path.realpath(__file__))
path = os.path.realpath(os.path.join(path, '..', 'lib', 'python'))
if path.startswith('/opt'):
# if installed into system path, do not muck with things
sys.path.append(path)
import confluent.client as client
import confluent.tlvdata as tlvdata
try:
input = raw_input
except NameError:
pass
def make_certificate():
umask = os.umask(0o77)
try:
os.makedirs('/etc/confluent/cfg')
except OSError as e:
if e.errno == errno.EEXIST and os.path.isdir('/etc/confluent/cfg'):
pass
else:
raise
if subprocess.check_call(
'openssl ecparam -name secp384r1 -genkey -out '
'/etc/confluent/privkey.pem'.split(' ')):
raise Exception('Error generating private key')
if subprocess.check_call('openssl req -new -x509 -key '
'/etc/confluent/privkey.pem -days 7300 -out '
'/etc/confluent/srvcert.pem -subj /CN='
'{0}'.format(socket.gethostname()).split(' ')):
raise Exception('Error generating certificate')
print('Certificate generated successfully')
os.umask(umask)
def show_invitation(name):
if not os.path.exists('/etc/confluent/srvcert.pem'):
make_certificate()
s = client.Command().connection
tlvdata.send(s, {'collective': {'operation': 'invite', 'name': name}})
invite = tlvdata.recv(s)['collective']
if 'error' in invite:
sys.stderr.write(invite['error'] + '\n')
return
print('{0}'.format(invite['invitation']))
def join_collective(server, invitation):
if not os.path.exists('/etc/confluent/srvcert.pem'):
make_certificate()
s = client.Command().connection
while not invitation:
invitation = input('Paste the invitation here: ')
tlvdata.send(s, {'collective': {'operation': 'join',
'invitation': invitation,
'server': server}})
res = tlvdata.recv(s)
res = res.get('collective',
{'status': 'Unknown response: ' + repr(res)})
print(res.get('status', res.get('error', repr(res))))
if 'error' in res:
sys.exit(1)
def delete_member(name):
s = client.Command().connection
tlvdata.send(s, {'collective': {'operation': 'delete',
'member': name}})
res = tlvdata.recv(s)
res = res.get('collective',
{'status': 'Unknown response: ' + repr(res)})
print(res.get('status', res.get('error', repr(res))))
if 'error' in res:
sys.exit(1)
def show_collective():
s = client.Command().connection
tlvdata.send(s, {'collective': {'operation': 'show'}})
res = tlvdata.recv(s)
if 'error' in res['collective']:
print(res['collective']['error'])
return
if 'quorum' in res['collective']:
print('Quorum: {0}'.format(res['collective']['quorum']))
print('Leader: {0}'.format(res['collective']['leader']))
if 'active' in res['collective']:
if res['collective']['active']:
print('Active collective members:')
for member in res['collective']['active']:
print(' {0}'.format(member))
if res['collective']['offline']:
print('Offline collective members:')
for member in res['collective']['offline']:
print(' {0}'.format(member))
else:
print('Run collective show on leader for more data')
def main():
a = argparse.ArgumentParser(description='Confluent server utility')
sp = a.add_subparsers(dest='command')
gc = sp.add_parser('gencert', help='Generate Confluent Certificates for '
'collective mode and remote CLI access')
sl = sp.add_parser('show', help='Show information about the collective')
ic = sp.add_parser('invite', help='Generate a invitation to allow a new '
'confluent instance to join as a '
'collective member. Run collective invite -h for more information')
ic.add_argument('name', help='Name of server to invite to join the '
'collective')
dc = sp.add_parser('delete', help='Delete a member of a collective')
dc.add_argument('name', help='Name of server to delete from collective')
jc = sp.add_parser('join', help='Join a collective. Run collective join -h for more information')
jc.add_argument('server', help='Existing collective member that ran invite and generated a token')
jc.add_argument('-i', help='Invitation provided by runniing invite on an '
'existing collective member')
cmdset = a.parse_args()
if cmdset.command == 'gencert':
make_certificate()
elif cmdset.command == 'invite':
show_invitation(cmdset.name)
elif cmdset.command == 'join':
join_collective(cmdset.server, cmdset.i)
elif cmdset.command == 'show':
show_collective()
elif cmdset.command == 'delete':
delete_member(cmdset.name)
if __name__ == '__main__':
main()
+1 -1
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/python2
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2014 IBM Corporation
+55
View File
@@ -0,0 +1,55 @@
from os.path import exists
import shutil
import socket
import subprocess
import tempfile
def get_openssl_conf_location():
if exists('/etc/pki/tls/openssl.cnf'):
return '/etc/pki/tls/openssl.cnf'
elif exists('/etc/ssl/openssl.cnf');
return '/etc/ssl/openssl.cnf'
else:
raise Exception("Cannot find openssl config file")
def get_ip_addresses():
lines = subprocess.check_output('ip addr'.split(' '))
for line in lines.split('\n'):
if line.startswith(' inet6 '):
line = line.replace(' inet6 ', '').split('/')[0]
if line.startswith('fe80::'):
continue
if line == '::1':
continue
elif line.startswith(' inet '):
line = line.replace(' inet ', '').split('/')[0]
if line == '127.0.0.1':
continue
if line.startswith('169.254.'):
continue
else:
continue
yield line
def create_certificate():
shortname = socket.gethostname().split('.')[0]
longname = socket.getfqdn()
subprocess.check_call(
'openssl ecparam -name secp384r1 -genkey -out privkey.pem'.split(' '))
san = ['IP:{0}'.format(x) for x in get_ip_addresses()]
san.append('DNS:{0}'.format(shortname))
san.append('DNS:{0}'.format(longname))
san = ','.join(san)
sslcfg = get_openssl_conf_location()
tmpconfig = tempfile.mktemp()
shutil.copy2(sslcfg, tmpconfig)
with open(tmpconfig, 'a') as cfgfile:
cfgfile.write('\n[SAN]\nsubjectAltName={0}'.format(san))
subprocess.check_call(
'openssl req -new -x509 -key privkey.pem -days 7300 -out cert.pem '
'-subj /CN={0} -extensions SAN '
'-config {1}'.format(longname, tmpconfig).split(' ')
)
if __name__ == '__main__':
create_certificate()
+34 -8
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/python2
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2017 Lenovo
@@ -16,6 +16,7 @@
# limitations under the License.
import getpass
import optparse
import sys
import os
@@ -32,6 +33,8 @@ argparser = optparse.OptionParser(
usage="Usage: %prog [options] [dump|restore] [path]")
argparser.add_option('-p', '--password',
help='Password to use to protect/unlock a protected dump')
argparser.add_option('-i', '--interactivepassword', help='Prompt for password',
action='store_true')
argparser.add_option('-r', '--redact', action='store_true',
help='Redact potentially sensitive data rather than store')
argparser.add_option('-u', '--unprotected', action='store_true',
@@ -39,6 +42,14 @@ argparser.add_option('-u', '--unprotected', action='store_true',
' the key information. Fields will be encrypted, '
'but keys.json will contain unencrypted decryption'
' keys that may be used to read the dump')
argparser.add_option('-s', '--skipkeys', action='store_true',
help='This specifies to dump the encrypted data without '
'dumping the keys needed to decrypt it. This is '
'suitable for an automated incremental backup, '
'where an earlier password protected dump has a '
'protected keys.json file, and only the protected '
'data is needed. keys do not change and as such '
'they do not require incremental backup')
(options, args) = argparser.parse_args()
if len(args) != 2 or args[0] not in ('dump', 'restore'):
argparser.print_help()
@@ -51,17 +62,32 @@ if args[0] == 'restore':
if pid is not None:
print("Confluent is running, must shut down to restore db")
sys.exit(1)
cfm.restore_db_from_directory(dumpdir, options.password)
elif args[0] == 'dump':
if options.password is None and not (options.unprotected or options.redact):
print("Must indicate a password to protect or -u to opt opt of "
"secure value protection or -r to skip all protected data")
try:
cfm.restore_db_from_directory(dumpdir, options.password)
except Exception as e:
print(str(e))
sys.exit(1)
os.umask(077)
elif args[0] == 'dump':
password = options.password
if not password and options.interactivepassword:
passcfm = None
while passcfm is None or password != passcfm:
password = getpass.getpass(
'Enter password to protect the backup: ')
passcfm = getpass.getpass('Confirm password to protect the backup: ')
if password is None and not (options.unprotected or options.redact
or options.skipkeys):
print("Must indicate a password to protect or -u to opt opt of "
"secure value protection or -r to redact sensitive information, "
"or -s to do encrypted backup that requires keys.json from "
"another backup to restore.")
sys.exit(1)
os.umask(0o77)
main._initsecurity(conf.get_config())
if not os.path.exists(dumpdir):
os.makedirs(dumpdir)
cfm.dump_db_to_directory(dumpdir, options.password, options.redact)
cfm.dump_db_to_directory(dumpdir, options.password, options.redact,
options.skipkeys)
+1 -1
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/python2
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2014 IBM Corporation
+4
View File
@@ -0,0 +1,4 @@
#!/bin/bash
umask 0077
openssl ecparam -name secp384r1 -genkey -out /etc/confluent/privkey.pem
openssl req -new -x509 -key /etc/confluent/privkey.pem -days 760 -out /etc/confluent/srvcert.pem -subj /CN=$(hostname)
+64
View File
@@ -0,0 +1,64 @@
#!/bin/bash
cd `dirname $0`
PKGNAME=$(basename $(pwd))
DPKGNAME=$(basename $(pwd) | sed -e s/_/-/)
OPKGNAME=$(basename $(pwd) | sed -e s/_/-/)
if grep wheezy /etc/os-release; then
DPKGNAME=python-$DPKGNAME
fi
cd ..
mkdir -p /tmp/confluent # $DPKGNAME
cp -a * .git /tmp/confluent # $DPKGNAME
cd /tmp/confluent/$PKGNAME
if [ -x ./makeman ]; then
./makeman
fi
./makesetup
VERSION=`cat VERSION`
cat > setup.cfg << EOF
[install]
install-purelib=/opt/confluent/lib/python
install-scripts=/opt/confluent/bin
[sdist_dsc]
package=$DPKGNAME
EOF
python setup.py sdist > /dev/null 2>&1
py2dsc dist/*.tar.gz
shopt -s extglob
cd deb_dist/!(*.orig)/
if [ "$OPKGNAME" = "confluent-server" ]; then
if grep wheezy /etc/os-release; then
sed -i 's/^\(Depends:.*\)/\1, python-confluent-client, python-lxml, python-eficompressor, python-pycryptodomex, python-dateutil, python-pyopenssl/' debian/control
else
sed -i 's/^\(Depends:.*\)/\1, confluent-client, python-lxml, python-eficompressor, python-pycryptodome, python-dateutil, python-websocket/' debian/control
fi
if grep wheezy /etc/os-release; then
echo 'confluent_client python-confluent-client' >> debian/pydist-overrides
else
echo 'confluent_client confluent-client' >> debian/pydist-overrides
fi
fi
head -n -1 debian/control > debian/control1
mv debian/control1 debian/control
echo 'export PYBUILD_INSTALL_ARGS=--install-lib=/opt/confluent/lib/python' >> debian/rules
#echo 'Provides: python-'$DPKGNAME >> debian/control
#echo 'Conflicts: python-'$DPKGNAME >> debian/control
#echo 'Replaces: python-'$DPKGNAME' (<<2)' >> debian/control
#echo 'Breaks: python-'$DPKGNAME' (<<2)' >> debian/control
dpkg-buildpackage -rfakeroot -uc -us -i
if [ $? -ne 0 ]; then
echo "[ERROR] rpmbuild returned non-zero, run: rpmbuild -ba ~/rpmbuild/SPECS/$PKGNAME.spec"
exit 1
else
cd -
# Clean up the generated files in this directory
rm -rf $PKGNAME.egg-info dist setup.py
rm -rf $(find deb_dist -mindepth 1 -maxdepth 1 -type d)
if [ ! -z "$1" ]; then
mv deb_dist/* $1/
fi
fi
exit 0
+4 -1
View File
@@ -1,9 +1,12 @@
#!/bin/sh
cd `dirname $0`
if [ -x ./makeman ]; then
./makeman
fi
./makesetup
VERSION=`cat VERSION`
PKGNAME=$(basename $(pwd))
python setup.py sdist > /dev/null 2>&1
python3 setup.py sdist > /dev/null 2>&1
cp dist/*.tar.gz ~/rpmbuild/SOURCES
sed -e 's/#VERSION#/'$VERSION/ $PKGNAME.spec.tmpl > ~/rpmbuild/SPECS/$PKGNAME.spec
rpmbuild -ba ~/rpmbuild/SPECS/$PKGNAME.spec 2> /dev/null |grep ^Wrote:
+7 -1
View File
@@ -1,6 +1,6 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2016 Lenovo
# Copyright 2016-2018 Lenovo
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -83,6 +83,8 @@ class AsyncSession(object):
self.reaper = eventlet.spawn_after(15, self.destroy)
def add(self, requestid, rsp):
if self.responses is None:
return
self.responses.append((requestid, rsp))
if self._evt:
self._evt.send()
@@ -107,6 +109,7 @@ class AsyncSession(object):
for console in self.consoles:
_consolesessions[console]['session'].destroy()
self.consoles = None
self.responses = None
del _asyncsessions[self.asyncid]
def run_handler(self, handler, requestid):
@@ -166,6 +169,9 @@ def handle_async(env, querydict, threadset):
currsess = AsyncSession()
yield messages.AsyncSession(currsess.asyncid)
return
if querydict['asyncid'] not in _asyncsessions:
raise exc.InvalidArgumentException(
'Invalid or expired async id')
mythreadid = greenlet.getcurrent()
threadset.add(mythreadid)
loggedout = None
+141 -78
View File
@@ -22,12 +22,16 @@
import confluent.config.configmanager as configmanager
import eventlet
import eventlet.tpool
import Crypto.Protocol.KDF as KDF
import Cryptodome.Protocol.KDF as KDF
from fnmatch import fnmatch
import hashlib
import hmac
import multiprocessing
import confluent.userutil as userutil
import confluent.util as util
pam = None
try:
import PAM
import confluent.pam as pam
except ImportError:
pass
import time
@@ -39,24 +43,59 @@ _passchecking = {}
authworkers = None
authcleaner = None
_allowedbyrole = {
'Operator': {
'retrieve': ['*'],
'create': [
'/noderange/',
'/nodes/',
'/node*/media/uploads/',
'/node*/inventory/firmware/updates/*',
'/node*/suppport/servicedata*',
'/node*/attributes/expression',
'/nodes/*/console/session*',
'/nodes/*/shell/sessions*',
'/node*/configuration/*',
],
'update': [
'/discovery/*',
'/networking/macs/rescan',
'/node*/power/state',
'/node*/power/reseat',
'/node*/attributes/*',
'/node*/media/*tach',
'/node*/boot/nextdevice',
'/node*/identify',
'/node*/configuration/*',
],
'start': [
'/nodes/*/console/session*',
'/nodes/*/shell/sessions*',
],
'delete': [
'/discovery/*',
'/node*',
],
},
'Monitor': {
'retrieve': [
'/node*/health/hardware',
'/node*/power/state',
'/node*/sensors/*',
'/nodes/',
'/',
],
}
}
class Credentials(object):
def __init__(self, username, passphrase):
self.username = username
self.passphrase = passphrase
self.haspam = False
def pam_conv(self, auth, query_list):
# use stored credentials in a pam conversation
self.haspam = True
resp = []
for query_entry in query_list:
query, pamtype = query_entry
if query.startswith('Password'):
resp.append((self.passphrase, 0))
else:
return None
return resp
_deniedbyrole = {
# This supersedes the above and is only consulted after the allowed has happened
'Operator': {
'update': [
'/node*/configuration/management_controller/users/*',
]
}
}
def _prune_passcache():
@@ -65,9 +104,9 @@ def _prune_passcache():
while True:
curtime = time.time()
for passent in _passcache.iterkeys():
if passent[2] < curtime - 10:
if passent[2] < curtime - 90:
del _passcache[passent]
eventlet.sleep(10)
eventlet.sleep(90)
def _get_usertenant(name, tenant=False):
@@ -81,11 +120,13 @@ def _get_usertenant(name, tenant=False):
administrator account a tenant gets.
Otherwise, just assume a user in the default tenant
"""
if not isinstance(name, bytes):
name = name.encode('utf-8')
if not isinstance(tenant, bool):
# if not boolean, it must be explicit tenant
user = name
elif '/' in name: # tenant scoped name
tenant, user = name.split('/', 1)
elif b'/' in name: # tenant scoped name
tenant, user = name.split(b'/', 1)
elif configmanager.is_tenant(name):
# the account is the implicit tenant owner account
user = name
@@ -93,6 +134,9 @@ def _get_usertenant(name, tenant=False):
else: # assume it is a non-tenant user account
user = name
tenant = None
user = util.stringify(user)
if tenant:
tenant = util.stringify(tenant)
yield user
yield tenant
@@ -112,21 +156,37 @@ def authorize(name, element, tenant=False, operation='create',
and the relevant ConfigManager object for the context of the
request.
"""
if operation not in ('create', 'start', 'update', 'retrieve', 'delete'):
return None
# skipuserobj is a leftover from the now abandoned plan to use pam session
# to do authorization and authentication. Now confluent always does authorization
# even if pam does authentication.
if operation not in ('create', 'start', 'update', 'retrieve', 'delete', None):
return False
user, tenant = _get_usertenant(name, tenant)
if tenant is not None and not configmanager.is_tenant(tenant):
return None
return False
manager = configmanager.ConfigManager(tenant, username=user)
if skipuserobj:
return None, manager, user, tenant, skipuserobj
userobj = manager.get_user(user)
if not userobj:
for group in userutil.grouplist(user):
userobj = manager.get_usergroup(group)
if userobj:
break
if userobj: # returning
role = userobj.get('role', 'Administrator')
if element and role != 'Administrator':
for rule in _allowedbyrole.get(role, {}).get(operation, []):
if fnmatch(element, rule):
break
else:
return False
for rule in _deniedbyrole.get(role, {}).get(operation, []):
if fnmatch(element, rule):
return False
return userobj, manager, user, tenant, skipuserobj
return None
return False
def check_user_passphrase(name, passphrase, element=None, tenant=False):
def check_user_passphrase(name, passphrase, operation=None, element=None, tenant=False):
"""Check a a login name and passphrase for authenticity and authorization
The function combines authentication and authorization into one function.
@@ -157,63 +217,66 @@ def check_user_passphrase(name, passphrase, element=None, tenant=False):
# would normally make an event and wait
# but here there's no need for that
eventlet.sleep(0.5)
credobj = Credentials(user, passphrase)
try:
pammy = PAM.pam()
pammy.start(_pamservice, user, credobj.pam_conv)
pammy.authenticate()
pammy.acct_mgmt()
del pammy
return authorize(user, element, tenant, skipuserobj=False)
except NameError:
pass
except PAM.error:
if credobj.haspam:
return None
cfm = configmanager.ConfigManager(tenant, username=user)
ucfg = cfm.get_user(user)
if ucfg is None:
try:
for group in userutil.grouplist(user):
ucfg = cfm.get_usergroup(group)
if ucfg:
break
except KeyError:
pass
if ucfg is None:
eventlet.sleep(0.05)
return None
if (user, tenant) in _passcache:
if passphrase == _passcache[(user, tenant)]:
return authorize(user, element, tenant)
if hashlib.sha256(passphrase).digest() == _passcache[(user, tenant)]:
return authorize(user, element, tenant, operation=operation)
else:
# In case of someone trying to guess,
# while someone is legitimately logged in
# invalidate cache and force the slower check
del _passcache[(user, tenant)]
return None
cfm = configmanager.ConfigManager(tenant, username=user)
ucfg = cfm.get_user(user)
if ucfg is None or 'cryptpass' not in ucfg:
eventlet.sleep(0.05) # stall even on test for existence of a username
return None
_passchecking[(user, tenant)] = True
# TODO(jbjohnso): WORKERPOOL
# PBKDF2 is, by design, cpu intensive
# throw it at the worker pool when implemented
# maybe a distinct worker pool, wondering about starving out non-auth stuff
salt, crypt = ucfg['cryptpass']
# execute inside tpool to get greenthreads to give it a special thread
# world
#TODO(jbjohnso): util function to generically offload a call
#such a beast could be passed into pyghmi as a way for pyghmi to
#magically get offload of the crypto functions without having
#to explicitly get into the eventlet tpool game
global authworkers
global authcleaner
if authworkers is None:
authworkers = multiprocessing.Pool(processes=1)
else:
authcleaner.cancel()
authcleaner = eventlet.spawn_after(30, _clean_authworkers)
crypted = eventlet.tpool.execute(_do_pbkdf, passphrase, salt)
del _passchecking[(user, tenant)]
eventlet.sleep(0.05) # either way, we want to stall so that client can't
if 'cryptpass' in ucfg:
_passchecking[(user, tenant)] = True
# TODO(jbjohnso): WORKERPOOL
# PBKDF2 is, by design, cpu intensive
# throw it at the worker pool when implemented
# maybe a distinct worker pool, wondering about starving out non-auth stuff
salt, crypt = ucfg['cryptpass']
# execute inside tpool to get greenthreads to give it a special thread
# world
# TODO(jbjohnso): util function to generically offload a call
# such a beast could be passed into pyghmi as a way for pyghmi to
# magically get offload of the crypto functions without having
# to explicitly get into the eventlet tpool game
global authworkers
global authcleaner
if authworkers is None:
authworkers = multiprocessing.Pool(processes=1)
else:
authcleaner.cancel()
authcleaner = eventlet.spawn_after(30, _clean_authworkers)
crypted = eventlet.tpool.execute(_do_pbkdf, passphrase, salt)
del _passchecking[(user, tenant)]
eventlet.sleep(
0.05) # either way, we want to stall so that client can't
# determine failure because there is a delay, valid response will
# delay as well
if crypt == crypted:
_passcache[(user, tenant)] = passphrase
return authorize(user, element, tenant)
if crypt == crypted:
_passcache[(user, tenant)] = hashlib.sha256(passphrase).digest()
return authorize(user, element, tenant, operation)
if pam:
pammy = pam.pam()
usergood = pammy.authenticate(user, passphrase)
del pammy
if usergood:
_passcache[(user, tenant)] = hashlib.sha256(passphrase).digest()
return authorize(user, element, tenant, operation, skipuserobj=False)
eventlet.sleep(0.05) # stall even on test for existence of a username
return None
def _apply_pbkdf(passphrase, salt):
return KDF.PBKDF2(passphrase, salt, 32, 10000,
lambda p, s: hmac.new(p, s, hashlib.sha256).digest())
@@ -231,4 +294,4 @@ def _do_pbkdf(passphrase, salt):
# compute. However, we do want to wait for result, so we have
# one of the exceedingly rare sort of circumstances where 'apply'
# actually makes sense
return authworkers.apply(_apply_pbkdf, [passphrase, salt])
return authworkers.apply(_apply_pbkdf, [passphrase, salt])
@@ -0,0 +1,60 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2018 Lenovo
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# This handles the process of generating and tracking/validating invites
import base64
import hashlib
import hmac
import os
pending_invites = {}
def create_server_invitation(servername):
servername = servername.encode('utf-8')
randbytes = (3 - ((len(servername) + 2) % 3)) % 3 + 64
invitation = os.urandom(randbytes)
pending_invites[servername] = invitation
return base64.b64encode(servername + b'@' + invitation)
def create_client_proof(invitation, mycert, peercert):
return hmac.new(invitation, peercert + mycert, hashlib.sha256).digest()
def check_server_proof(invitation, mycert, peercert, proof):
validproof = hmac.new(invitation, mycert + peercert, hashlib.sha256
).digest()
return proof == validproof
def check_client_proof(servername, mycert, peercert, proof):
servername = servername.encode('utf-8')
if servername not in pending_invites:
return False
invitation = pending_invites[servername]
validproof = hmac.new(invitation, mycert + peercert, hashlib.sha256
).digest()
if proof == validproof:
# We know that the client knew the secret, and that it measured our
# certificate, and thus calling code can bless the certificate, and
# we can forget the invitation
del pending_invites[servername]
# We now want to prove to the client that we also know the secret,
# and that we measured their certificate well
# Now to generate an answer...., reverse the cert order so our answer
# is different, but still proving things
return hmac.new(invitation, peercert + mycert, hashlib.sha256
).digest()
# The given proof did not verify the invitation
return False

Some files were not shown because too many files have changed in this diff Show More