#!/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 [list|upload|attach|detachall] " "|all|", 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()