From b90718982efb2bd1895a4c2b1fa2c587da217de7 Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Mon, 22 Jan 2024 17:22:47 -0500 Subject: [PATCH] Implement a number of OS deployment management enhancements. Add capability to fingerprint media without doing a full import (/deployment/fingerprinting/) Add fetching the profile info as json under the /deployment/ api. Prepare to support custom distribution name on import --- confluent_server/confluent/core.py | 36 +++++++++++++++++++--- confluent_server/confluent/mountmanager.py | 1 + confluent_server/confluent/osimage.py | 36 ++++++++++++++-------- 3 files changed, 56 insertions(+), 17 deletions(-) diff --git a/confluent_server/confluent/core.py b/confluent_server/confluent/core.py index f21d36b5..a8a4412b 100644 --- a/confluent_server/confluent/core.py +++ b/confluent_server/confluent/core.py @@ -70,6 +70,7 @@ import os import eventlet.green.socket as socket import struct import sys +import yaml pluginmap = {} dispatch_plugins = (b'ipmi', u'ipmi', b'redfish', u'redfish', b'tsmsol', u'tsmsol', b'geist', u'geist', b'deltapdu', u'deltapdu', b'eatonpdu', u'eatonpdu', b'affluent', u'affluent', b'cnos', u'cnos') @@ -177,6 +178,7 @@ def handle_storage(configmanager, inputdata, pathcomponents, operation): if pathcomponents[1] == 'remote': for rsp in mountmanager.handle_request(configmanager, inputdata, pathcomponents[2:], operation): yield rsp + def handle_deployment(configmanager, inputdata, pathcomponents, operation): if len(pathcomponents) == 1: @@ -199,8 +201,19 @@ def handle_deployment(configmanager, inputdata, pathcomponents, for prof in osimage.list_profiles(): yield msg.ChildCollection(prof + '/') return - if len(pathcomponents) == 3: - profname = pathcomponents[-1] + if len(pathcomponents) >= 3: + profname = pathcomponents[2] + if len(pathcomponents) == 4: + if operation == 'retrieve': + if len(pathcomponents) == 4 and pathcomponents[-1] == 'info': + with open('/var/lib/confluent/public/os/{}/profile.yaml'.format(profname)) as profyaml: + profinfo = yaml.safe_load(profyaml) + profinfo['name'] = profname + yield msg.KeyValueData(profinfo) + return + elif len(pathcomponents) == 3: + if operation == 'retrieve': + yield msg.ChildCollection('info') if operation == 'update': if 'updateboot' in inputdata: osimage.update_boot(profname) @@ -216,6 +229,17 @@ def handle_deployment(configmanager, inputdata, pathcomponents, for cust in customized: yield msg.KeyValueData({'customized': cust}) return + if pathcomponents[1] == 'fingerprint': + if operation == 'create': + importer = osimage.MediaImporter(inputdata['filename'], configmanager, checkonly=True) + medinfo = { + 'targetpath': importer.targpath, + 'name': importer.osname, + 'oscategory': importer.oscategory, + 'errors': importer.errors, + } + yield msg.KeyValueData(medinfo) + return if pathcomponents[1] == 'importing': if len(pathcomponents) == 2 or not pathcomponents[-1]: if operation == 'retrieve': @@ -223,8 +247,12 @@ def handle_deployment(configmanager, inputdata, pathcomponents, yield imp return elif operation == 'create': - importer = osimage.MediaImporter(inputdata['filename'], - configmanager) + if inputdata.get('custname', None): + importer = osimage.MediaImporter(inputdata['filename'], + configmanager, inputdata['custname']) + else: + importer = osimage.MediaImporter(inputdata['filename'], + configmanager) yield msg.KeyValueData({'target': importer.targpath, 'name': importer.importkey}) return diff --git a/confluent_server/confluent/mountmanager.py b/confluent_server/confluent/mountmanager.py index c73b87a2..c6c10bc1 100644 --- a/confluent_server/confluent/mountmanager.py +++ b/confluent_server/confluent/mountmanager.py @@ -28,6 +28,7 @@ def handle_request(configmanager, inputdata, pathcomponents, operation): mountsbyuser[curruser].append(currmount) yield msg.KeyValueData({ 'path': currmount['path'], + 'fullpath': '/var/run/confluent/browserfs/mount/{}'.format(currmount['path']), 'authtoken': currmount['authtoken'] }) diff --git a/confluent_server/confluent/osimage.py b/confluent_server/confluent/osimage.py index 8884e0e9..969e05b4 100644 --- a/confluent_server/confluent/osimage.py +++ b/confluent_server/confluent/osimage.py @@ -747,9 +747,9 @@ def rebase_profile(dirname): # customization detected, skip # else # update required, manifest update - - - + + + def get_hashes(dirname): hashmap = {} for dname, _, fnames in os.walk(dirname): @@ -776,7 +776,7 @@ def generate_stock_profiles(defprofile, distpath, targpath, osname, continue oumask = os.umask(0o22) shutil.copytree(srcname, dirname) - hmap = get_hashes(dirname) + hmap = get_hashes(dirname) profdata = None try: os.makedirs('{0}/boot/initramfs'.format(dirname), 0o755) @@ -824,11 +824,12 @@ def generate_stock_profiles(defprofile, distpath, targpath, osname, class MediaImporter(object): - def __init__(self, media, cfm=None): + def __init__(self, media, cfm=None, customname=None, checkonly=False): self.worker = None if not os.path.exists('/var/lib/confluent/public'): raise Exception('`osdeploy initialize` must be executed before importing any media') self.profiles = [] + self.errors = [] medfile = None self.medfile = None if cfm and media in cfm.clientfiles: @@ -848,25 +849,34 @@ class MediaImporter(object): self.phase = 'copying' if not identity: raise Exception('Unrecognized OS Media') - if 'subname' in identity: + if customname: + importkey = customname + elif 'subname' in identity: importkey = '{0}-{1}'.format(identity['name'], identity['subname']) else: importkey = identity['name'] - if importkey in importing: + if importkey in importing and not checkonly: raise Exception('Media import already in progress for this media') self.importkey = importkey - importing[importkey] = self - self.importkey = importkey self.osname = identity['name'] self.oscategory = identity.get('category', None) - targpath = identity['name'] + if customname: + targpath = customname + else: + targpath = identity['name'] self.distpath = '/var/lib/confluent/distributions/' + targpath - if identity.get('subname', None): + if identity.get('subname', None): # subname is to indicate disk number in a media set targpath += '/' + identity['subname'] self.targpath = '/var/lib/confluent/distributions/' + targpath if os.path.exists(self.targpath): - del importing[importkey] - raise Exception('{0} already exists'.format(self.targpath)) + errstr = '{0} already exists'.format(self.targpath) + if checkonly: + self.errors = [errstr] + else: + raise Exception(errstr) + if checkonly: + return + importing[importkey] = self self.filename = os.path.abspath(media) self.error = '' self.importer = eventlet.spawn(self.importmedia)