def channels(prefix): """ Show channels. """ mqstate.validate(['host', 'port', 'channel']) args = {pymqi.CMQCFC.MQCACH_CHANNEL_NAME: prefix.encode()} qmgr = pymqi.connect(mqstate.qm_name, mqstate.channel, mqstate.get_host(), mqstate.username, mqstate.password) pcf = pymqi.PCFExecute(qmgr) try: click.secho(f'Showing channels with prefix: "{prefix}"...\n', dim=True) response = pcf.MQCMD_INQUIRE_CHANNEL(args) except pymqi.MQMIError as sce: if sce.comp == pymqi.CMQC.MQCC_FAILED and sce.reason == pymqi.CMQC.MQRC_UNKNOWN_OBJECT_NAME: click.secho(f'No channels matched prefix {prefix}', fg='red') else: raise sce else: t = get_table_handle([ 'Name', 'Type', 'MCA UID', 'Conn Name', 'Xmit Queue', 'Description', 'SSL Cipher', ]) for channel_info in response: t.append_row([ mq_string( channel_info.get(pymqi.CMQCFC.MQCACH_CHANNEL_NAME, '')), channel_type_to_name( channel_info.get(pymqi.CMQCFC.MQIACH_CHANNEL_TYPE)), mq_string(channel_info.get(pymqi.CMQCFC.MQCACH_MCA_USER_ID, '')), mq_string( channel_info.get(pymqi.CMQCFC.MQCACH_CONNECTION_NAME, '')), mq_string(channel_info.get(pymqi.CMQCFC.MQCACH_XMIT_Q_NAME, '')), mq_string(channel_info.get(pymqi.CMQCFC.MQCACH_DESC, '')), mq_string( channel_info.get(pymqi.CMQCFC.MQCACH_SSL_CIPHER_SPEC, '')), ]) click.secho(t.get_string()) qmgr.disconnect()
def pop(queue, save_to, skip_confirmation): """ Pop a message off the queue. """ if not skip_confirmation: click.secho( 'WARNING: This action will REMOVE the message from the selected queue!\n' + 'Consider the --save-to flag to save the message you are about to pop.', fg='yellow') if not click.confirm('Are you sure?'): click.secho('Did not receive confirmation, bailing...') return qmgr = pymqi.connect(mqstate.qm_name, mqstate.channel, mqstate.get_host(), mqstate.username, mqstate.password) try: queue = pymqi.Queue(qmgr, str(queue)) request_md = pymqi.MD() message = queue.get(None, request_md) except pymqi.MQMIError as dme: if dme.comp == pymqi.CMQC.MQCC_FAILED and dme.reason == pymqi.CMQC.MQRC_NO_MSG_AVAILABLE: click.secho('No messages to pop from the queue.', fg='yellow') return else: raise dme t = get_table_handle( ['Date', 'Time', 'User', 'Format', 'App Name', 'Data'], markdown=False) t.append_row([ mq_string(request_md.PutDate), mq_string(request_md.PutTime), mq_string(request_md.UserIdentifier), mq_string(request_md.Format), mq_string(request_md.PutApplName), mq_string(message), ]) click.secho('') click.secho(t.get_string()) # save to file if we got a file argument if save_to: save_to.write(message) click.secho(f'\nSaved message data to file: {save_to.name}', fg='green') queue.close() qmgr.disconnect()
def save(queue, limit, directory): """ Save messages from a queue to a file, non-destructively. """ mqstate.validate(['host', 'port', 'channel']) # Automatically generate a directory to save messages to if not directory: directory = safe_filename(mqstate.host + '_' + safe_filename(queue)) click.secho(f'Saving messages to \'{directory}\'...', dim=True, fg='green') # check that the directory is ready for use absolute_path = os.path.abspath(directory) if not os.path.exists(absolute_path): click.secho(f'Creating {absolute_path} to save messages in...', dim=True) os.makedirs(absolute_path, mode=0o755) click.secho(f'Saving a maximum of {limit} messages from {queue}...', dim=True) qmgr = pymqi.connect(mqstate.qm_name, mqstate.channel, mqstate.get_host(), mqstate.username, mqstate.password) # https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_7.5.0/com.ibm.mq.ref.dev.doc/q096780_.htm # https://github.com/dsuch/pymqi/blob/master/code/examples/put_get_correl_id.py gmo = pymqi.GMO() gmo.Options = pymqi.CMQC.MQGMO_BROWSE_NEXT queue = pymqi.Queue(qmgr, str(queue), pymqi.CMQC.MQOO_BROWSE) message_count = 0 while message_count < limit: try: request_md = pymqi.MD() message = queue.get(None, request_md, gmo) file_name = filename_from_attributes( mq_string(request_md.PutDate), mq_string(request_md.PutTime), '.' + hashlib.sha1(request_md.MsgId).hexdigest() + '.', request_md.MsgType, request_md.Expiry, mq_string(request_md.UserIdentifier), mq_string(request_md.Format), mq_string(request_md.PutApplName)) # try get a safe filename from all of that file_name = slugify(file_name) with open(os.path.join(absolute_path, file_name), 'wb') as f: f.write(message) click.secho(f'{message_count}: Wrote message to {file_name}', bold=True, fg='green') except pymqi.MQMIError as dme: if dme.comp == pymqi.CMQC.MQCC_FAILED and dme.reason == pymqi.CMQC.MQRC_NO_MSG_AVAILABLE: click.secho('Dump complete. No more messages on the queue.', fg='yellow') break # if we are not allowed to GET on this queue, mention that and quit if dme.comp == pymqi.CMQ.MQCC_FAILED and dme.reason == pymqi.CMQC.MQRC_GET_INHIBITED: click.secho('GET not allowed on queue with current access.', fg='red') break else: raise dme message_count += 1 click.secho(f'Saved {message_count} message(s) in total.', bold=True) queue.close() qmgr.disconnect()
def sniff(queue, store, directory): """ Sniff messages on a queue, non-destructively. Sniffs queues messages on a queue by opening the queue in a read only mode. Incoming messages will be dumped to the screen by default. If the --store flag is specified, messages will also be written to disk as they arrive. """ mqstate.validate(['host', 'port']) # check if a directory was set but store was not if directory and not store: click.secho('A directory was set to store messages but --store flag was not provided, ignoring...', bold=True, fg='yellow') # Prepare the destination directory if messages should also be saved if store: # Automatically generate a directory to save messages to if not directory: directory = safe_filename(mqstate.host + '_' + safe_filename(queue)) click.secho(f'Messages will be saved to directory \'{directory}\'', dim=True, fg='green') # check that the directory is ready for use absolute_path = os.path.abspath(directory) if not os.path.exists(absolute_path): click.secho(f'Creating {absolute_path} to save messages in...', dim=True) os.makedirs(absolute_path, mode=0o755) qmgr = pymqi.connect(mqstate.qm_name, mqstate.channel, mqstate.get_host(), mqstate.username, mqstate.password) # https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_7.5.0/com.ibm.mq.ref.dev.doc/q096780_.htm # https://github.com/dsuch/pymqi/blob/master/code/examples/put_get_correl_id.py # https://github.com/dsuch/pymqi/blob/master/code/examples/get_wait_multiple_messages.py gmo = pymqi.GMO() gmo.Options = pymqi.CMQC.MQGMO_BROWSE_NEXT | pymqi.CMQC.MQGMO_WAIT | pymqi.CMQC.MQGMO_FAIL_IF_QUIESCING gmo.WaitInterval = 2 * 1000 # 5 seconds queue = pymqi.Queue(qmgr, str(queue), pymqi.CMQC.MQOO_BROWSE) request_md = pymqi.MD() # simple counter for statistics message_count = 0 click.secho('Waiting for messages to arrive...', dim=True) while True: try: # grab the message message = queue.get(None, request_md, gmo) message_count += 1 # Save the message if we need to we do this early as # messages could be reformatted to be printed to screen. if store: file_name = filename_from_attributes( mq_string(request_md.PutDate), mq_string(request_md.PutTime), '.' + hashlib.sha1(request_md.MsgId).hexdigest() + '.', request_md.MsgType, request_md.Expiry, mq_string(request_md.UserIdentifier), mq_string(request_md.Format), mq_string(request_md.PutApplName)) # try get a safe filename from all of that file_name = slugify(file_name) with open(os.path.join(absolute_path, file_name), 'wb') as f: f.write(message) click.secho(f'{message_count}: Wrote message to {file_name}', bold=True, fg='green') # check if we have a MQSTR message. If we don't, try and filter # non-printables. if request_md.Format.strip() not in ['MQSTR', '']: # remove non-printables and update the Format # column with (stripped) so that it is visible message = message.decode('ascii', errors='ignore') request_md.Format = mq_string(request_md.Format) + ' (stripped)' click.secho(f'Message #{message_count}', fg='green') table = get_table_handle([ 'Date', 'Time', 'MsgID', 'MsgType', 'Expiry', 'User', 'Format', 'App Name'], markdown=False) table.append_row([ mq_string(request_md.PutDate), mq_string(request_md.PutTime), request_md.MsgId.decode('ascii', errors='ignore'), request_md.MsgType, request_md.Expiry, mq_string(request_md.UserIdentifier), mq_string(request_md.Format), mq_string(request_md.PutApplName), ]) # Print a 'header' for the message click.secho(table.get_string()) # Print the message itself click.secho('' + '*' * 40 + ' BEGIN MESSAGE DATA ' + '*' * 40, dim=True) click.secho(message, bold=True) click.secho('*' * 41 + ' END MESSAGE DATA ' + '*' * 41 + '\n', dim=True) # reset the request descriptor so we can reuse it for the next message. request_md.MsgId = pymqi.CMQC.MQMI_NONE request_md.CorrelId = pymqi.CMQC.MQCI_NONE request_md.GroupId = pymqi.CMQC.MQGI_NONE request_md.Format = pymqi.CMQC.MQGI_NONE except pymqi.MQMIError as dme: # No messages, that's OK, we can ignore it. if dme.comp == pymqi.CMQC.MQCC_FAILED and dme.reason == pymqi.CMQC.MQRC_NO_MSG_AVAILABLE: continue # if we are not allowed to GET on this queue, mention that and quit if dme.comp == pymqi.CMQ.MQCC_FAILED and dme.reason == pymqi.CMQC.MQRC_GET_INHIBITED: click.secho('GET not allowed on queue with current credentials.', fg='red') break else: # Some other error condition. raise dme except KeyboardInterrupt as _: click.secho('Stopping...', fg='yellow') break click.secho(f'\nSniffed {message_count} message(s) in total.', dim=True) queue.close() qmgr.disconnect()
def dump(queue, limit): """ Dump messages from a queue, non-destructively. """ click.secho(f'Dumping a maximum of {limit} messages from {queue}...', dim=True) click.secho('Only printing ASCII characters.', dim=True) qmgr = pymqi.connect(mqstate.qm_name, mqstate.channel, mqstate.get_host(), mqstate.username, mqstate.password) # https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_7.5.0/com.ibm.mq.ref.dev.doc/q096780_.htm # https://github.com/dsuch/pymqi/blob/master/code/examples/put_get_correl_id.py gmo = pymqi.GMO() gmo.Options = pymqi.CMQC.MQGMO_BROWSE_NEXT queue = pymqi.Queue(qmgr, str(queue), pymqi.CMQC.MQOO_BROWSE) message_count = 0 while message_count < limit: try: request_md = pymqi.MD() message = queue.get(None, request_md, gmo) # check if we have a MQSTR message. if request_md.Format.strip() not in ['MQSTR', '']: # remove non-printables and update the Format # column with (stripped) so that it is visible message = message.decode('ascii', errors='ignore') request_md.Format = mq_string(request_md.Format) + ' (stripped)' table = get_table_handle(['Date', 'Time', 'MsgID', 'MsgType', 'Expiry', 'User', 'Format', 'App Name'], markdown=False) table.append_row([ mq_string(request_md.PutDate), mq_string(request_md.PutTime), request_md.MsgId.decode('ascii', errors='ignore'), request_md.MsgType, request_md.Expiry, mq_string(request_md.UserIdentifier), mq_string(request_md.Format), mq_string(request_md.PutApplName), ]) # Print a 'header' for the message click.secho(table.get_string()) # Print the message itself click.secho('\n' + '*' * 40 + ' BEGIN MESSAGE DATA ' + '*' * 40, dim=True) click.secho(message, bold=True) click.secho('*' * 41 + ' END MESSAGE DATA ' + '*' * 41 + '\n', dim=True) except pymqi.MQMIError as dme: if dme.comp == pymqi.CMQC.MQCC_FAILED and dme.reason == pymqi.CMQC.MQRC_NO_MSG_AVAILABLE: click.secho('Dump complete. No more messages on the queue.', fg='yellow') break # if we are not allowed to GET on this queue, mention that and quit if dme.comp == pymqi.CMQ.MQCC_FAILED and dme.reason == pymqi.CMQC.MQRC_GET_INHIBITED: click.secho('GET not allowed on queue with current access.', fg='red') break else: raise dme message_count += 1 click.secho('') click.secho(f'\nGot {message_count} message(s) in total.', dim=True) queue.close() qmgr.disconnect()
def queues(prefix, min_depth): """ Show queues. """ mqstate.validate(['host', 'port', 'channel']) args = { pymqi.CMQC.MQCA_Q_NAME: prefix.encode(), pymqi.CMQC.MQIA_Q_TYPE: pymqi.CMQC.MQQT_ALL } qmgr = pymqi.connect(mqstate.qm_name, mqstate.channel, mqstate.get_host(), mqstate.username, mqstate.password) pcf = pymqi.PCFExecute(qmgr) try: click.secho(f'Showing queues with prefix: "{prefix}"...', dim=True) if min_depth > 0: click.secho(f'Limiting queues to those with at least {min_depth} message(s)...', dim=True) response = pcf.MQCMD_INQUIRE_Q(args) except pymqi.MQMIError as sqe: # no queues found if sqe.comp == pymqi.CMQC.MQCC_FAILED and sqe.reason == pymqi.CMQC.MQRC_UNKNOWN_OBJECT_NAME: click.secho(f'No queues matched given prefix of {prefix}', fg='red') else: raise sqe else: t = get_table_handle([ 'Created', 'Name', 'Type', 'Usage', 'Depth', 'Rmt. QMGR Name', 'Rmt. Queue Name', 'Description', ], markdown=True) t.set_style(t.STYLE_MARKDOWN) for queue_info in response: # skip queues that don't have at least the min amount of messages if queue_info.get(pymqi.CMQC.MQIA_CURRENT_Q_DEPTH, 0) < min_depth: continue # try and resolve the transmission queue for remote queue types q_type = queue_type_to_name(queue_info.get(pymqi.CMQC.MQIA_Q_TYPE)) if q_type == 'Remote': xmit_q = mq_string(queue_info.get(pymqi.CMQC.MQCA_XMIT_Q_NAME, '')) if len(xmit_q) > 0: q_type = q_type + f' (Transmission Q: {xmit_q})' t.append_row([ ' '.join([ mq_string(queue_info.get(pymqi.CMQC.MQCA_CREATION_DATE, '')), mq_string(queue_info.get(pymqi.CMQC.MQCA_CREATION_TIME, '')) ]), mq_string(queue_info.get(pymqi.CMQC.MQCA_Q_NAME, '')), q_type, queue_usage_to_name(queue_info.get(pymqi.CMQC.MQIA_USAGE)), queue_info.get(pymqi.CMQC.MQIA_CURRENT_Q_DEPTH, ''), mq_string(queue_info.get(pymqi.CMQC.MQCA_REMOTE_Q_MGR_NAME, '')), mq_string(queue_info.get(pymqi.CMQC.MQCA_REMOTE_Q_NAME, '')), mq_string(queue_info.get(pymqi.CMQC.MQCA_Q_DESC, '')), ]) click.secho(t.get_string()) qmgr.disconnect()