From 730d80d52645a5f860fa0cd8dc980a9a5849a698 Mon Sep 17 00:00:00 2001 From: Geoff Gatward Date: Mon, 19 Dec 2016 16:19:08 +1100 Subject: [PATCH] Add manifest export --- README.md | 9 +++ bin/download_manifest | 12 +++ config/config.yml.example | 1 + download_manifest.py | 152 ++++++++++++++++++++++++++++++++++++++ helpers.py | 1 + sat6_scripts.spec | 2 + sat_export.py | 16 ++++ 7 files changed, 193 insertions(+) create mode 100755 bin/download_manifest create mode 100755 download_manifest.py diff --git a/README.md b/README.md index 5158294..76b93b1 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,7 @@ satellite: username: svc-api-user password: 1t$a$3cr3t disconnected: [True|False] (Is direct internet connection available?) + manifest: my-satellite (Red Hat Portal satellite application name) default_org: MyOrg (Default org to use - can be overridden with -o) logging: @@ -77,6 +78,14 @@ tasks that have stopped but been marked as Incomplete. Running with the -l flag will loop the check until terminated with CTRL-C +# download_manifest +Script originally written by Rich Jerrido downloads subscription manifest from +Red Hat portal. Need to provide a username (-l) with access to download the +manifest. Manifest name is configured in config.yml, but can be overridden on the +command line with the (-s) option. Manifest is downloaded to the the configured +export directory, and included in the bundle generated by sat_export. + + # sat_export Intended to perform content export from a Connected Satellite (Sync Host), for transfer into a disconnected environment. The Default Organization View (DOV) diff --git a/bin/download_manifest b/bin/download_manifest new file mode 100755 index 0000000..1f35871 --- /dev/null +++ b/bin/download_manifest @@ -0,0 +1,12 @@ +#!/usr/bin/python +import sys + +#sys.path.insert(0, '/usr/share/sat6_scripts') +sys.path.insert(0, '/usr/local/bin/sat6_scripts') +try: + import download_manifest + download_manifest.main(sys.argv[1:]) +except KeyboardInterrupt, e: + print >> sys.stderr, "\n\nExiting on user cancel." + sys.exit(1) + diff --git a/config/config.yml.example b/config/config.yml.example index 6ff8239..6d7daaf 100644 --- a/config/config.yml.example +++ b/config/config.yml.example @@ -3,6 +3,7 @@ satellite: username: svc-api-user password: 1t$a$3cr3t default_org: MyOrg + manifest: my-satellite disconnected: False logging: diff --git a/download_manifest.py b/download_manifest.py new file mode 100755 index 0000000..2f11b40 --- /dev/null +++ b/download_manifest.py @@ -0,0 +1,152 @@ +#!/usr/bin/env python + +# File: rhsmDownloadManifest.py +# Author: Rich Jerrido +# Purpose: Given a username, password & +# Subscription Management Application, +# Download its manifest +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +import json +import getpass +import urllib2 +import base64 +import sys +import ssl +import datetime +from optparse import OptionParser +# ggatward: Additional imports for sat6_scripts integration +import helpers +import os, shutil + +parser = OptionParser() +parser.add_option("-l", "--login", dest="login", help="Login user for RHSM", metavar="LOGIN") +parser.add_option("-p", "--password", dest="password", help="Password for specified user. Will prompt if omitted", + metavar="PASSWORD") +parser.add_option("-d", "--debug", dest='debug', help="print more details for debugging", default=False, + action='store_true') +parser.add_option("-s", "--subscription-management-app", dest='sma', + help="Which Subscription Management Application to download manifests from", metavar="SMA") +parser.add_option("--host", dest='portal_host', help="RHSM host to use (Default subscription.rhn.redhat.com)", + default="subscription.rhn.redhat.com") +(options, args) = parser.parse_args() + +if not (options.login): + print "Must specify a login (will prompt for password if omitted). See usage:" + parser.print_help() + print "\nExample usage: ./rhsmDownloadManifest.py -l rh_user_account -s My_Satellite" + sys.exit(1) +else: + login = options.login + password = options.password + portal_host = options.portal_host + +if options.sma: + sma = options.sma +else: + sma = helpers.MANIFEST + +if not password: + password = getpass.getpass("%s's password:" % login) + +if hasattr(ssl, '_create_unverified_context'): + ssl._create_default_https_context = ssl._create_unverified_context + +# ggatward: Change timestamp format +timestamp = datetime.datetime.now().strftime("%Y%m%d") + +# ggatward: Use existing sat-export directory structure +# Remove any existing manifests so we only grab the current one +EXPORTDIR = helpers.EXPORTDIR + '/manifest' +if os.path.exists(EXPORTDIR): + shutil.rmtree(helpers.EXPORTDIR + '/manifest') + os.makedirs(EXPORTDIR) +else: + os.makedirs(EXPORTDIR) + +# Grab the Candlepin account number +url = "https://" + portal_host + "/subscription/users/" + login + "/owners/" +try: + if options.debug: + print "Attempting to connect: " + url + request = urllib2.Request(url) + base64string = base64.encodestring('%s:%s' % (login, password)).strip() + request.add_header("Authorization", "Basic %s" % base64string) + result = urllib2.urlopen(request) +except urllib2.HTTPError, e: + print "Error: cannot connect to the API due to HTTP Error: %s" % e.code + sys.exit(1) +except urllib2.URLError, e: + print "Error: cannot connect to the API: %s" % e + print "Check your URL & try to login using the same user/pass via the WebUI and check the error!" + sys.exit(1) + +accountdata = json.load(result) +for accounts in accountdata: + acct = accounts["key"] + +# Grab a list of Consumers +url = "https://" + portal_host + "/subscription/owners/" + acct + "/consumers/" + +try: + if options.debug: + print "Attempting to connect: " + url + request = urllib2.Request(url) + base64string = base64.encodestring('%s:%s' % (login, password)).strip() + request.add_header("Authorization", "Basic %s" % base64string) + result = urllib2.urlopen(request) +except urllib2.HTTPError, e: + print "Error: cannot connect to the API due to HTTP Error: %s" % e.code + sys.exit(1) +except urllib2.URLError, e: + print "Error: cannot connect to the API: %s" % e + print "Check your URL & try to login using the same user/pass via the WebUI and check the error!" + sys.exit(1) + +consumerdata = json.load(result) + +# Now that we have a list of Consumers, loop through them and +# see if one matches our + +for consumer in consumerdata: + consumerType = consumer["type"]["label"] + uuid = consumer["uuid"] + consumerName = consumer["name"] + if consumerType in ['satellite', 'sam']: + if sma == consumerName: + url = "https://" + portal_host + "/subscription/consumers/" + uuid + "/export/" + if options.debug: + print "\tAttempting to connect: " + url + print "\tSubscription Management Application %s matches parameters. Exporting..." % sma + try: + request = urllib2.Request(url) + base64string = base64.encodestring('%s:%s' % (login, password)).strip() + request.add_header("Authorization", "Basic %s" % base64string) + result = urllib2.urlopen(request) + # ggatward: Updated export location and name formatting + manifest_file = EXPORTDIR + "/manifest_%s_%s.zip" % (consumerName, timestamp) + if options.debug: + print "\tWriting Manifest to %s" % manifest_file + with open(manifest_file, "wb") as manifest: + manifest.write(result.read()) + sys.exit(0) + except urllib2.HTTPError, e: + print "Error: cannot connect to the API due to HTTP Error: %s" % e.code + sys.exit(1) + except urllib2.URLError, e: + print "Error: cannot connect to the API: %s" % e + print "Check your URL & try to login using the same user/pass via the WebUI and check the error!" + sys.exit(1) + +print "The Subscription Management Application %s could not be found" % sma +print "Reminder: names are case-sensitive" +sys.exit(0) + diff --git a/helpers.py b/helpers.py index f404310..79b09b2 100644 --- a/helpers.py +++ b/helpers.py @@ -37,6 +37,7 @@ USERNAME = CONFIG["satellite"]["username"] PASSWORD = CONFIG["satellite"]["password"] DISCONNECTED = CONFIG["satellite"]["disconnected"] +MANIFEST = CONFIG["satellite"]["manifest"] ORG_NAME = CONFIG["satellite"]["default_org"] LOGDIR = CONFIG["logging"]["dir"] DEBUG = CONFIG["logging"]["debug"] diff --git a/sat6_scripts.spec b/sat6_scripts.spec index acabed0..d7c7255 100644 --- a/sat6_scripts.spec +++ b/sat6_scripts.spec @@ -41,6 +41,7 @@ install -m 0644 sat_import.py %{buildroot}/usr/share/sat6_scripts/sat_import.py install -m 0644 publish_content_views.py %{buildroot}/usr/share/sat6_scripts/publish_content_views.py install -m 0644 promote_content_views.py %{buildroot}/usr/share/sat6_scripts/promote_content_views.py install -m 0644 clean_content_views.py %{buildroot}/usr/share/sat6_scripts/clean_content_views.py +install -m 0644 download_manifest.py %{buildroot}/usr/share/sat6_scripts/download_manifest.py @@ -57,6 +58,7 @@ install -m 0644 clean_content_views.py %{buildroot}/usr/share/sat6_scripts/clean /usr/share/sat6_scripts/publish_content_views.py /usr/share/sat6_scripts/promote_content_views.py /usr/share/sat6_scripts/clean_content_views.py +/usr/share/sat6_scripts/download_manifest.py /usr/local/bin/check_sync /usr/local/bin/sat_export diff --git a/sat_export.py b/sat_export.py index 947c3c5..352548b 100755 --- a/sat_export.py +++ b/sat_export.py @@ -285,6 +285,19 @@ def export_puppet(repo_id, repo_label, repo_relative, last_export, export_type, return numfiles +def export_manifest(): + """ + Copies manifest downloaded by 'download_manifest.py' into the export bundle + """ + if os.path.exists(helpers.EXPORTDIR + '/manifest'): + msg = 'Found manifest to export' + helpers.log_msg(msg, 'DEBUG') + MFSTEXPORTDIR = helpers.EXPORTDIR + '/export/manifest' + if not os.path.exists(MFSTEXPORTDIR): + os.makedirs(MFSTEXPORTDIR) + os.system('cp ' + helpers.EXPORTDIR + '/manifest/* ' + MFSTEXPORTDIR) + + def count_packages(repo_id): """ Return the number of packages/erratum in a respository @@ -1000,6 +1013,9 @@ def main(args): if not args.nogpg: do_gpg_check(export_dir) + # Copy in the manifest, if it has been downloaded + export_manifest() + # Add our exported data to a tarfile create_tar(export_dir, ename)