def decommission_asset_cp(updated_asset, asset_cp, change_plan): asset_data = RecursiveAssetSerializer(updated_asset).data asset_data["live_id"] = asset_data["id"] del asset_data["id"] asset_data["decommissioning_user"] = str(change_plan.owner) decommissioned_asset = AddDecommissionedAssetSerializer(data=asset_data) if not decommissioned_asset.is_valid(raise_exception=False): return JsonResponse( { "failure_message": Status.INVALID_INPUT.value + parse_serializer_errors(decommissioned_asset.errors), "errors": str(decommissioned_asset.errors), }, status=HTTPStatus.BAD_REQUEST, ) try: decommissioned_asset.save() except Exception as error: return JsonResponse( { "failure_message": Status.DECOMMISSION_ERROR.value + parse_save_validation_error(error, "Decommissioned Asset "), "errors": str(error), }, status=HTTPStatus.BAD_REQUEST, ) else: updated_asset.delete()
def change_plan_add(request): """ Add a new change plan """ data = JSONParser().parse(request) if "id" in data: return JsonResponse( { "failure_message": Status.CREATE_ERROR.value + GenericFailure.INTERNAL.value, "errors": "Don't include 'id' when creating a change planner", }, status=HTTPStatus.BAD_REQUEST, ) data["owner"] = request.user.id serializer = AddChangePlanSerializer(data=data) if not serializer.is_valid(raise_exception=False): return JsonResponse( { "failure_message": Status.INVALID_INPUT.value + parse_serializer_errors(serializer.errors), "errors": str(serializer.errors), }, status=HTTPStatus.BAD_REQUEST, ) try: change_plan = serializer.save() except Exception as error: return JsonResponse( { "failure_message": Status.CREATE_ERROR.value + parse_save_validation_error(error, "Change Plan"), "errors": str(error), }, status=HTTPStatus.BAD_REQUEST, ) return JsonResponse( { "success_message": Status.SUCCESS.value + "Change Plan " + str(change_plan.name) + " created", "related_id": str(change_plan.id), }, status=HTTPStatus.OK, )
def change_plan_modify(request): """ Modify single existing change plan """ data = JSONParser().parse(request) if "id" not in data: return JsonResponse( { "failure_message": Status.MODIFY_ERROR.value + GenericFailure.INTERNAL.value, "errors": "Must include 'id' when modifying a change plan", }, status=HTTPStatus.BAD_REQUEST, ) id = data["id"] (existing_change_plan, failure_response) = get_change_plan(id) if failure_response: return failure_response failure_response = get_cp_already_executed_response(existing_change_plan) if failure_response: return failure_response for field in data.keys(): value = data[field] setattr(existing_change_plan, field, value) try: existing_change_plan.save() return JsonResponse( { "success_message": Status.SUCCESS.value + "Change Plan " + str(existing_change_plan.name) + " modified", "related_id": str(existing_change_plan.id), }, status=HTTPStatus.OK, ) except Exception as error: return JsonResponse( { "failure_message": Status.MODIFY_ERROR.value + parse_save_validation_error(error, "Asset"), "errors": str(error), }, status=HTTPStatus.BAD_REQUEST, )
def save_all_field_data_live(data, asset): asset_id = data["id"] for field in data.keys(): if field == "model" and data["model"]: value = ITModel.objects.get(id=data[field]) elif field == "rack" and data["rack"]: value = Rack.objects.get(id=data[field]) elif field == "chassis" and data["chassis"]: value = Asset.objects.get(id=data[field]) elif field == "offline_storage_site" and data["offline_storage_site"]: value = Site.objects.get(id=data[field]) elif field == "hostname" and data["hostname"]: assets_with_hostname = Asset.objects.filter(hostname__iexact=data[field]) if len(assets_with_hostname) > 0 and assets_with_hostname[0].id != asset_id: return ( "Asset with hostname '" + data[field].lower() + "' already exists." ) value = data[field] elif field == "asset_number": try: int(data[field]) except ValueError: return data[field] + " is not a valid hostname. Asset number must be a number between 100000 and 999999" assets_with_asset_number = Asset.objects.filter(asset_number=data[field]) if ( data[field] and len(assets_with_asset_number) > 0 and assets_with_asset_number[0].id != asset.id ): return ( "Asset with asset number '" + str(data[field]) + "' already exists." ) value = data[field] else: value = data[field] if field is not "id": setattr(asset, field, value) try: asset.save() except Exception as error: return parse_save_validation_error(error, "Asset")
def asset_add(request): """ Add a new asset. """ data = JSONParser().parse(request) if "id" in data: return JsonResponse( { "failure_message": Status.CREATE_ERROR.value + GenericFailure.INTERNAL.value, "errors": "Don't include 'id' when creating an asset", }, status=HTTPStatus.BAD_REQUEST, ) (change_plan, failure_response) = get_change_plan( request.query_params.get("change_plan") ) if failure_response: return failure_response chassis_id_live = None if change_plan: failure_response = get_cp_already_executed_response(change_plan) if failure_response: return failure_response data["change_plan"] = change_plan.id if data["chassis"] and not AssetCP.objects.filter(id=data["chassis"]).exists(): # ignore the chassis because we will replace it with a new chassis on AssetCP later chassis_id_live = data["chassis"] del data["chassis"] serializer = AssetCPSerializer(data=data) else: serializer = AssetSerializer(data=data) if not serializer.is_valid(raise_exception=False): return JsonResponse( { "failure_message": Status.INVALID_INPUT.value + parse_serializer_errors(serializer.errors), "errors": str(serializer.errors), }, status=HTTPStatus.BAD_REQUEST, ) try: validate_user_permission_on_new_asset_data( request.user, serializer.validated_data, data_is_validated=True, change_plan=change_plan, chassis_id_live=chassis_id_live, ) except UserAssetPermissionException as auth_error: return JsonResponse( {"failure_message": Status.AUTH_ERROR.value + str(auth_error)}, status=HTTPStatus.UNAUTHORIZED, ) except Exception as error: return JsonResponse( {"failure_message": Status.CREATE_ERROR.value + str(error)}, status=HTTPStatus.BAD_REQUEST, ) if not ( "offline_storage_site" in serializer.validated_data and serializer.validated_data["offline_storage_site"] ): if serializer.validated_data["model"].is_rackmount(): if ( "rack" not in serializer.validated_data or not serializer.validated_data["rack"] or "rack_position" not in serializer.validated_data or not serializer.validated_data["rack_position"] ): return JsonResponse( { "failure_message": Status.INVALID_INPUT.value + "Must include rack and rack position to add a rackmount asset. " }, status=HTTPStatus.BAD_REQUEST, ) rack_id = serializer.validated_data["rack"].id rack_position = serializer.validated_data["rack_position"] height = serializer.validated_data["model"].height try: validate_asset_location_in_rack( rack_id, rack_position, height, change_plan=change_plan ) except LocationException as error: return JsonResponse( {"failure_message": Status.CREATE_ERROR.value + str(error)}, status=HTTPStatus.BAD_REQUEST, ) else: if ( ( ( "chassis" not in serializer.validated_data or not serializer.validated_data["chassis"] ) and not chassis_id_live ) or "chassis_slot" not in serializer.validated_data or not serializer.validated_data["chassis_slot"] ): return JsonResponse( { "failure_message": Status.INVALID_INPUT.value + "Must include chassis and chassis slot to add a blade asset. " }, status=HTTPStatus.BAD_REQUEST, ) if chassis_id_live: try: chassis_live = Asset.objects.get(id=chassis_id_live) except ObjectDoesNotExist: return JsonResponse( { "failure_message": Status.MODIFY_ERROR.value + "Chassis" + GenericFailure.DOES_NOT_EXIST.value, "errors": "No existing chassis with id=" + str(chassis_id_live), }, status=HTTPStatus.BAD_REQUEST, ) chassis_cp = add_chassis_to_cp(chassis_live, change_plan) chassis_id = chassis_cp.id serializer.validated_data["chassis"] = chassis_cp else: chassis_id = serializer.validated_data["chassis"].id chassis_slot = serializer.validated_data["chassis_slot"] try: validate_asset_location_in_chassis( chassis_id, chassis_slot, change_plan=change_plan ) except LocationException as error: return JsonResponse( {"failure_message": Status.CREATE_ERROR.value + str(error)}, status=HTTPStatus.BAD_REQUEST, ) try: asset = serializer.save() except Exception as error: return JsonResponse( { "failure_message": Status.CREATE_ERROR.value + parse_save_validation_error(error, "Asset"), "errors": str(error), }, status=HTTPStatus.BAD_REQUEST, ) warning_message = save_all_connection_data( data, asset, request.user, change_plan=change_plan ) if warning_message: return JsonResponse({"warning_message": warning_message}, status=HTTPStatus.OK) if change_plan: return JsonResponse( { "success_message": Status.SUCCESS.value + "Asset created on change plan " + change_plan.name, "related_id": change_plan.id, }, status=HTTPStatus.OK, ) else: log_action(request.user, asset, Action.CREATE) return JsonResponse( { "success_message": Status.SUCCESS.value + "Asset " + str(asset.asset_number) + " created" }, status=HTTPStatus.OK, )
def decommission_asset_parameterized(asset_id, query_params, user, change_plan): """ Decommission a live asset """ decommissioned_asset_cp = None if change_plan: response = get_cp_already_executed_response(change_plan) if response: return None, response assets, assets_cp = get_assets_for_cp(change_plan.id, show_decommissioned=True) if assets_cp.filter(related_asset=asset_id).exists(): decommissioned_asset_cp = assets_cp.get(related_asset=asset_id) decommissioned_asset_cp.is_decommissioned = True asset_id = decommissioned_asset_cp.id elif assets_cp.filter(id=asset_id).exists(): decommissioned_asset_cp = assets_cp.get(id=asset_id) decommissioned_asset_cp.is_decommissioned = True asset_id = decommissioned_asset_cp.id elif assets.filter(id=asset_id).exists(): existing_asset = assets.get(id=asset_id) if existing_asset.model.is_blade_chassis(): decommissioned_asset_cp = add_chassis_to_cp( existing_asset, change_plan) else: chassis_cp = None if existing_asset.model.is_blade_asset( ) and existing_asset.chassis: if not assets_cp.filter( related_asset=existing_asset.chassis.id).exists(): chassis_cp = add_chassis_to_cp( existing_asset.chassis, change_plan, ignore_blade_id=existing_asset.id, ) else: chassis_cp = assets_cp.get( related_asset=existing_asset.chassis.id) decommissioned_asset_cp = copy_asset_to_new_asset_cp( existing_asset, change_plan, chassis_cp=chassis_cp) decommissioned_asset_cp.is_decommissioned = True decommissioned_asset_cp.save() else: return ( None, JsonResponse( { "failure_message": Status.ERROR.value + "Asset" + GenericFailure.DOES_NOT_EXIST.value, "errors": "No existing asset in change plan with id=" + str(asset_id), }, status=HTTPStatus.BAD_REQUEST, ), ) try: validate_user_permission_on_existing_asset( user, decommissioned_asset_cp) except UserAssetPermissionException as auth_error: return ( None, JsonResponse( { "failure_message": Status.AUTH_ERROR.value + str(auth_error) }, status=HTTPStatus.UNAUTHORIZED, ), ) if asset_id != decommissioned_asset_cp.id: ## a new asset cp was created for decommissioning, blades are not on assetxp blades = assets.filter(chassis=asset_id) else: blades = assets_cp.filter(chassis=asset_id) for blade in blades: try: decommission_asset_parameterized(blade.id, query_params, user, change_plan) # Assume that if this call doesn't raise an exception, it was successful # None of the failed responses above are possible except Exception as error: return ( None, JsonResponse( { "failure_message": Status.DECOMMISSION_ERROR.value + "Unable to decommission blade: '" + str(blade.asset_number) + "'. ", "errors": str(error), }, status=HTTPStatus.BAD_REQUEST, ), ) try: decommissioned_asset_cp.save() except Exception as error: return ( None, JsonResponse( { "failure_message": Status.DECOMMISSION_ERROR.value + parse_save_validation_error(error, "Decommissioned Asset "), "errors": str(error), }, status=HTTPStatus.BAD_REQUEST, ), ) return ( JsonResponse( { "success_message": "Asset successfully decommissioned on change plan: " + change_plan.name }, status=HTTPStatus.OK, ), None, ) try: asset = Asset.objects.get(id=asset_id) except Asset.DoesNotExist: return ( None, JsonResponse( { "failure_message": Status.ERROR.value + "Asset" + GenericFailure.DOES_NOT_EXIST.value, "errors": "No existing asset with id=" + str(asset_id), }, status=HTTPStatus.BAD_REQUEST, ), ) try: validate_user_permission_on_existing_asset(user, asset) except UserAssetPermissionException as auth_error: return ( None, JsonResponse( {"failure_message": Status.AUTH_ERROR.value + str(auth_error)}, status=HTTPStatus.UNAUTHORIZED, ), ) blades = Asset.objects.filter(chassis=asset.id) for blade in blades: try: decommission_asset_parameterized(blade.id, query_params, user, change_plan) # Assume that if this call doesn't raise an exception, it was successful # None of the failed responses above are possible except Exception as error: return ( None, JsonResponse( { "failure_message": Status.DECOMMISSION_ERROR.value + "Unable to decommission blade: '" + str(blade.asset_number) + "'. ", "errors": str(error), }, status=HTTPStatus.BAD_REQUEST, ), ) asset_data = RecursiveAssetSerializer(asset).data asset_data["live_id"] = asset_data["id"] del asset_data["id"] asset_data["decommissioning_user"] = str(user) decommissioned_asset = AddDecommissionedAssetSerializer(data=asset_data) if not decommissioned_asset.is_valid(raise_exception=False): return ( None, JsonResponse( { "failure_message": Status.INVALID_INPUT.value + parse_serializer_errors(decommissioned_asset.errors), "errors": str(decommissioned_asset.errors), }, status=HTTPStatus.BAD_REQUEST, ), ) try: decommissioned_asset_object = decommissioned_asset.save() except Exception as error: return ( None, JsonResponse( { "failure_message": Status.DECOMMISSION_ERROR.value + parse_save_validation_error(error, "Decommissioned Asset "), "errors": str(error), }, status=HTTPStatus.BAD_REQUEST, ), ) else: for assetcp in AssetCP.objects.filter(related_asset=asset_id): assetcp.related_decommissioned_asset = decommissioned_asset_object assetcp.save() log_action( user, asset, Action.DECOMMISSION, ) return ( JsonResponse( {"success_message": "Asset successfully decommissioned. "}, status=HTTPStatus.OK, ), None, )
def save_all_field_data_cp(data, asset, change_plan, create_asset_cp): asset_id = data["id"] for field in data.keys(): if field == "model" and data["model"]: value = ITModel.objects.get(id=data[field]) elif field == "rack" and data["rack"]: value = Rack.objects.get(id=data[field]) elif field == "offline_storage_site" and data["offline_storage_site"]: value = Site.objects.get(id=data[field]) elif field == "hostname" and data["hostname"]: assets, assets_cp = get_assets_for_cp(change_plan.id) assets_with_hostname = assets.filter(hostname__iexact=data[field]) if not ( len(assets_with_hostname) > 0 and assets_with_hostname[0].id != asset_id ): assets_with_hostname = assets_cp.filter(hostname__iexact=data[field]) if len(assets_with_hostname) > 0 and assets_with_hostname[0].id != asset_id: return ( None, "Asset with hostname '" + data[field].lower() + "' already exists.", ) value = data[field] elif field == "asset_number": if create_asset_cp: related_asset = asset else: related_asset = asset.related_asset try: validate_asset_number_uniqueness( data[field], asset_id, change_plan, related_asset, ) except ValidationError: return ( None, "Asset with asset number '" + str(data[field]) + "' already exists.", ) value = data[field] else: value = data[field] if field != "id" and field != "chassis": setattr(asset, field, value) chassis = None if data["chassis"]: try: chassis = AssetCP.objects.get(id=data["chassis"]) except ObjectDoesNotExist: if Asset.objects.filter(id=data["chassis"]).exists(): chassis_live = Asset.objects.get(id=data["chassis"]) chassis = add_chassis_to_cp( chassis_live, change_plan, ignore_blade_id=asset.id ) else: return ( None, "Chassis with id " + str(data["chassis"]) + " does not exist", ) try: if create_asset_cp: if asset.model.is_blade_chassis(): asset_cp = add_chassis_to_cp(asset, change_plan) else: asset_cp = copy_asset_to_new_asset_cp( asset, change_plan, chassis_cp=chassis ) asset_cp.save() return asset_cp, None else: asset.chassis = chassis asset.save() return asset, None except Exception as error: return None, parse_save_validation_error(error, "Asset")