def _recreate_webhook_configuration(self, app_op, app): webhook = self._get_webhook_configuration(app_op) if webhook: LOG.info( "Validating webhook already present on system. Nothing to be done." ) return dbapi_instance = app_op._dbapi db_app = dbapi_instance.kube_app_get(app.name) user_overrides = self._get_helm_user_overrides( dbapi_instance, db_app, app_constants.HELM_CHART_INGRESS_NGINX, app_constants.HELM_NS_NGINX_INGRESS_CONTROLLER, ) if REAPPLY_ADMISSION_WEBHOOK_OVERRIDE not in user_overrides: LOG.info( "Override for admission webhook not found. Nothing to be done." ) return original_overrides = user_overrides.replace( DISABLE_ADMISSION_WEBHOOK_OVERRIDE_CREATION, "").replace(REAPPLY_ADMISSION_WEBHOOK_OVERRIDE, "") updated_overrides = CREATE_ADMISSION_WEBHOOK_OVERRIDE + ": %s\n" % time( ) + original_overrides self._update_helm_user_overrides( dbapi_instance, db_app, app_constants.HELM_CHART_INGRESS_NGINX, app_constants.HELM_NS_NGINX_INGRESS_CONTROLLER, updated_overrides, ) # Reapply the application to ensure the validating webhook is recreated lifecycle_hook_info = LifecycleHookInfo() lifecycle_hook_info.operation = constants.APP_APPLY_OP app_op.perform_app_apply(app._kube_app, constants.APP_LIFECYCLE_MODE_AUTO, lifecycle_hook_info) if BACKUP_ADMISSION_WEBHOOK_OVERRIDE in original_overrides: original_overrides = original_overrides.replace( BACKUP_ADMISSION_WEBHOOK_OVERRIDE, CREATE_ADMISSION_WEBHOOK_OVERRIDE, ) self._update_helm_user_overrides( dbapi_instance, db_app, app_constants.HELM_CHART_INGRESS_NGINX, app_constants.HELM_NS_NGINX_INGRESS_CONTROLLER, original_overrides, )
def delete(self, name, force=None): """Delete the application with the given name :param name: application name """ try: db_app = objects.kube_app.get_by_name(pecan.request.context, name) except exception.KubeAppNotFound: LOG.error("Received a request to delete app %s which does not " "exist." % name) raise wsme.exc.ClientSideError( _("Application-delete rejected: application not found.")) if db_app.status not in [ constants.APP_UPLOAD_SUCCESS, constants.APP_UPLOAD_FAILURE ]: raise wsme.exc.ClientSideError( _("Application-delete rejected: operation is not allowed " "while the current status is {}.".format(db_app.status))) try: lifecycle_hook_info = LifecycleHookInfo() lifecycle_hook_info.init( constants.APP_LIFECYCLE_MODE_MANUAL, constants.APP_LIFECYCLE_TYPE_SEMANTIC_CHECK, constants.APP_LIFECYCLE_TIMING_PRE, constants.APP_DELETE_OP) # Converting string to boolean if force == 'True': force = True else: force = False lifecycle_hook_info.extra = { constants.APP_LIFECYCLE_FORCE_OPERATION: force } self._app_lifecycle_actions(db_app, lifecycle_hook_info) except rpc_common.RemoteError as e: raise wsme.exc.ClientSideError( _("Application-delete rejected: " + str(e.value))) except Exception as e: raise wsme.exc.ClientSideError( _("Application-delete rejected: " + six.text_type(e))) lifecycle_hook_info = LifecycleHookInfo() lifecycle_hook_info.mode = constants.APP_LIFECYCLE_MODE_MANUAL response = pecan.request.rpcapi.perform_app_delete( pecan.request.context, db_app, lifecycle_hook_info=lifecycle_hook_info) if response: raise wsme.exc.ClientSideError(_("%s." % response))
def post(self, body): """Uploading an application to be deployed by Armada""" tarfile = body.get('tarfile') name = body.get('name', '') version = body.get('app_version', '') name, version, mname, mfile = self._check_tarfile( tarfile, name, version, constants.APP_UPLOAD_OP) try: objects.kube_app.get_by_name(pecan.request.context, name) raise wsme.exc.ClientSideError( _("Application-upload rejected: application {} already exists." .format(name))) except exception.KubeAppNotFound: pass # Create a database entry and make an rpc async request to upload # the application app_data = { 'name': name, 'app_version': version, 'manifest_name': mname, 'manifest_file': os.path.basename(mfile), 'status': constants.APP_UPLOAD_IN_PROGRESS } try: new_app = pecan.request.dbapi.kube_app_create(app_data) except exception.SysinvException as e: LOG.exception(e) raise lifecycle_hook_info = LifecycleHookInfo() lifecycle_hook_info.mode = constants.APP_LIFECYCLE_MODE_MANUAL pecan.request.rpcapi.perform_app_upload( pecan.request.context, new_app, tarfile, lifecycle_hook_info=lifecycle_hook_info) return KubeApp.convert_with_links(new_app)
def update(self, body): """Update the applied application to a different version""" tarfile = body.get('tarfile') name = body.get('name', '') version = body.get('app_version', '') name, version, mname, mfile = self._check_tarfile( tarfile, name, version, constants.APP_UPDATE_OP) reuse_overrides_flag = body.get('reuse_user_overrides', None) if reuse_overrides_flag is None: # None means let the application decide reuse_overrides = None elif reuse_overrides_flag in ['true', 'True']: reuse_overrides = True elif reuse_overrides_flag in ['false', 'False']: reuse_overrides = False else: raise wsme.exc.ClientSideError( _("Application-update rejected: " "invalid reuse_user_overrides setting.")) try: applied_app = objects.kube_app.get_by_name(pecan.request.context, name) except exception.KubeAppNotFound: LOG.error( "Received a request to update app %s which does not exist." % name) raise wsme.exc.ClientSideError( _("Application-update rejected: application not found.")) try: lifecycle_hook_info = LifecycleHookInfo() lifecycle_hook_info.init( constants.APP_LIFECYCLE_MODE_MANUAL, constants.APP_LIFECYCLE_TYPE_SEMANTIC_CHECK, constants.APP_LIFECYCLE_TIMING_PRE, constants.APP_UPDATE_OP) self._app_lifecycle_actions(applied_app, lifecycle_hook_info) except Exception as e: raise wsme.exc.ClientSideError( _("Application-update rejected: " + str(e.message))) if applied_app.status == constants.APP_UPDATE_IN_PROGRESS: raise wsme.exc.ClientSideError( _("Application-update rejected: update is already " "in progress.")) elif applied_app.status != constants.APP_APPLY_SUCCESS: raise wsme.exc.ClientSideError( _("Application-update rejected: operation is not allowed " "while the current status is {}.".format( applied_app.status))) if applied_app.app_version == version: raise wsme.exc.ClientSideError( _("Application-update rejected: the version %s is already " "applied." % version)) # Set the status for the current applied app to inactive applied_app.status = constants.APP_INACTIVE_STATE applied_app.progress = None applied_app.save() # If the version has ever applied before(inactive app found), # use armada rollback to apply application later, otherwise, # use armada apply. # On the AIO-SX, always use armada apply even it was applied # before, issue on AIO-SX(replicas is 1) to leverage rollback, # armada/helm rollback --wait does not wait for pods to be # ready before it returns. # related to helm issue, # https://github.com/helm/helm/issues/4210 # https://github.com/helm/helm/issues/2006 try: target_app = objects.kube_app.get_inactive_app_by_name_version( pecan.request.context, name, version) target_app.status = constants.APP_UPDATE_IN_PROGRESS target_app.save() if cutils.is_aio_simplex_system(pecan.request.dbapi): operation = constants.APP_APPLY_OP else: operation = constants.APP_ROLLBACK_OP except exception.KubeAppInactiveNotFound: target_app_data = { 'name': name, 'app_version': version, 'manifest_name': mname, 'manifest_file': os.path.basename(mfile), 'status': constants.APP_UPDATE_IN_PROGRESS, 'active': True } operation = constants.APP_APPLY_OP try: target_app = pecan.request.dbapi.kube_app_create( target_app_data) except exception.KubeAppAlreadyExists as e: applied_app.status = constants.APP_APPLY_SUCCESS applied_app.progress = constants.APP_PROGRESS_COMPLETED applied_app.save() LOG.exception(e) raise wsme.exc.ClientSideError( _("Application-update failed: Unable to start application update, " "application info update failed.")) lifecycle_hook_info = LifecycleHookInfo() lifecycle_hook_info.mode = constants.APP_LIFECYCLE_MODE_MANUAL pecan.request.rpcapi.perform_app_update(pecan.request.context, applied_app, target_app, tarfile, operation, lifecycle_hook_info, reuse_overrides) return KubeApp.convert_with_links(target_app)
def patch(self, name, directive, values): """Install/update the specified application :param name: application name :param directive: either 'apply' (fresh install/update), 'remove' or 'abort' """ if directive not in ['apply', 'remove', 'abort']: raise exception.OperationNotPermitted try: db_app = objects.kube_app.get_by_name(pecan.request.context, name) except exception.KubeAppNotFound: LOG.error("Received a request to %s app %s which does not exist." % (directive, name)) raise wsme.exc.ClientSideError( _("Application-{} rejected: application not found.".format( directive))) if directive == 'apply': if not values: mode = None elif name not in constants.HELM_APP_APPLY_MODES.keys(): raise wsme.exc.ClientSideError( _("Application-apply rejected: Mode is not supported " "for app {}.".format(name))) elif (values['mode'] and values['mode'] not in constants.HELM_APP_APPLY_MODES[name]): raise wsme.exc.ClientSideError( _("Application-apply rejected: Mode {} for app {} is not " "valid. Valid modes are {}.".format( values['mode'], name, constants.HELM_APP_APPLY_MODES[name]))) else: mode = values['mode'] try: app_helper = KubeAppHelper(pecan.request.dbapi) app_helper._check_app_compatibility(db_app.name, db_app.app_version) except exception.IncompatibleKubeVersion as e: raise wsme.exc.ClientSideError( _("Application-apply rejected: " + str(e))) if db_app.status == constants.APP_APPLY_IN_PROGRESS: raise wsme.exc.ClientSideError( _("Application-apply rejected: install/update is already " "in progress.")) elif db_app.status not in [ constants.APP_UPLOAD_SUCCESS, constants.APP_APPLY_FAILURE, constants.APP_APPLY_SUCCESS ]: raise wsme.exc.ClientSideError( _("Application-apply rejected: operation is not allowed " "while the current status is {}.".format(db_app.status))) try: lifecycle_hook_info = LifecycleHookInfo() lifecycle_hook_info.init( constants.APP_LIFECYCLE_MODE_MANUAL, constants.APP_LIFECYCLE_TYPE_SEMANTIC_CHECK, constants.APP_LIFECYCLE_TIMING_PRE, constants.APP_APPLY_OP) self._app_lifecycle_actions(db_app, lifecycle_hook_info) except Exception as e: raise wsme.exc.ClientSideError( _("Application-apply rejected: " + str(e.message))) db_app.status = constants.APP_APPLY_IN_PROGRESS db_app.progress = None db_app.recovery_attempts = 0 db_app.mode = mode db_app.save() lifecycle_hook_info = LifecycleHookInfo() lifecycle_hook_info.mode = constants.APP_LIFECYCLE_MODE_MANUAL pecan.request.rpcapi.perform_app_apply( pecan.request.context, db_app, mode=mode, lifecycle_hook_info=lifecycle_hook_info) elif directive == 'remove': if db_app.status not in [ constants.APP_APPLY_SUCCESS, constants.APP_APPLY_FAILURE, constants.APP_REMOVE_FAILURE ]: raise wsme.exc.ClientSideError( _("Application-remove rejected: operation is not allowed while " "the current status is {}.".format(db_app.status))) try: lifecycle_hook_info = LifecycleHookInfo() lifecycle_hook_info.init( constants.APP_LIFECYCLE_MODE_MANUAL, constants.APP_LIFECYCLE_TYPE_SEMANTIC_CHECK, constants.APP_LIFECYCLE_TIMING_PRE, constants.APP_REMOVE_OP) self._app_lifecycle_actions(db_app, lifecycle_hook_info) except Exception as e: raise wsme.exc.ClientSideError( _("Application-remove rejected: " + str(e.message))) db_app.status = constants.APP_REMOVE_IN_PROGRESS db_app.progress = None db_app.save() lifecycle_hook_info = LifecycleHookInfo() lifecycle_hook_info.mode = constants.APP_LIFECYCLE_MODE_MANUAL pecan.request.rpcapi.perform_app_remove( pecan.request.context, db_app, lifecycle_hook_info=lifecycle_hook_info) else: if db_app.status not in [ constants.APP_APPLY_IN_PROGRESS, constants.APP_UPDATE_IN_PROGRESS, constants.APP_REMOVE_IN_PROGRESS ]: raise wsme.exc.ClientSideError( _("Application-abort rejected: operation is not allowed while " "the current status is {}.".format(db_app.status))) try: lifecycle_hook_info = LifecycleHookInfo() lifecycle_hook_info.init( constants.APP_LIFECYCLE_MODE_MANUAL, constants.APP_LIFECYCLE_TYPE_SEMANTIC_CHECK, constants.APP_LIFECYCLE_TIMING_PRE, constants.APP_ABORT_OP) self._app_lifecycle_actions(db_app, lifecycle_hook_info) except Exception as e: raise wsme.exc.ClientSideError( _("Application-abort rejected: " + str(e.message))) lifecycle_hook_info = LifecycleHookInfo() lifecycle_hook_info.mode = constants.APP_LIFECYCLE_MODE_MANUAL pecan.request.rpcapi.perform_app_abort( pecan.request.context, db_app, lifecycle_hook_info=lifecycle_hook_info) return KubeApp.convert_with_links(db_app)
def post(self, body): """Uploading an application to be deployed by Armada""" tarfile_path = body.get('tarfile') tarfile_binary = body.get('binary_data', '') name = body.get('name', '') version = body.get('app_version', '') images = body.get('images', False) if not cutils.is_url(tarfile_path) and not os.path.exists( tarfile_path): path_tarballs = '/tmp/tarball_uploads' if not os.path.exists(path_tarballs): os.makedirs(path_tarballs) uid, gid = pwd.getpwnam('sysinv').pw_uid, pwd.getpwnam( 'sysinv').pw_uid os.chown(path_tarballs, uid, gid) # Keep unique tarball name to avoid conflicts tarball_name = '{}-{}'.format(time.time(), os.path.basename(tarfile_path)) tarfile_path = os.path.join(path_tarballs, tarball_name) try: with open(tarfile_path, 'wb') as f: f.write(base64.urlsafe_b64decode(tarfile_binary)) except Exception as e: LOG.exception('Error: writing the tarfile: {}'.format(e)) raise wsme.exc.ClientSideError( _("Could not save the application on path {}".format( tarfile_path))) name, version, mname, mfile = self._check_tarfile( tarfile_path, name, version, constants.APP_UPLOAD_OP) try: objects.kube_app.get_by_name(pecan.request.context, name) raise wsme.exc.ClientSideError( _("Application-upload rejected: application {} already exists." .format(name))) except exception.KubeAppNotFound: pass # Create a database entry and make an rpc async request to upload # the application app_data = { 'name': name, 'app_version': version, 'manifest_name': mname, 'manifest_file': os.path.basename(mfile), 'status': constants.APP_UPLOAD_IN_PROGRESS } try: new_app = pecan.request.dbapi.kube_app_create(app_data) except exception.SysinvException as e: LOG.exception(e) raise lifecycle_hook_info = LifecycleHookInfo() lifecycle_hook_info.mode = constants.APP_LIFECYCLE_MODE_MANUAL pecan.request.rpcapi.perform_app_upload( pecan.request.context, new_app, tarfile_path, lifecycle_hook_info=lifecycle_hook_info, images=images) return KubeApp.convert_with_links(new_app)