Exemple #1
0
def rack_get(request):
    """
    List all racks within specified range.
    """
    range_serializer = RackRangeSerializer(data=request.data)

    if not range_serializer.is_valid():
        return JsonResponse(
            {
                "failure_message":
                Status.INVALID_INPUT.value +
                parse_serializer_errors(range_serializer.errors),
                "errors":
                str(range_serializer.errors),
            },
            status=HTTPStatus.BAD_REQUEST,
        )
    (change_plan, failure_response) = get_change_plan(
        request.query_params.get("change_plan"))
    if failure_response:
        return failure_response
    racks = Rack.objects.filter(
        datacenter=range_serializer.get_datacenter(),
        rack_num__range=range_serializer.get_number_range(),  # inclusive range
        row_letter__range=range_serializer.get_row_range(),
    )

    return get_rack_detailed_response(racks, change_plan)
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 site_create(request):
    """
    Add a site.
    """
    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 site",
            },
            status=HTTPStatus.BAD_REQUEST,
        )
    serializer = SiteSerializer(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:
        new_site = serializer.save()
    except Exception as error:
        return JsonResponse(
            {
                "failure_message":
                Status.CREATE_ERROR.value + "Site" +
                GenericFailure.ON_SAVE.value,
                "errors":
                str(error),
            },
            status=HTTPStatus.BAD_REQUEST,
        )
    log_action(request.user, new_site, Action.CREATE)
    return JsonResponse(
        {
            "success_message":
            Status.SUCCESS.value + new_site.abbreviation + " created"
        },
        status=HTTPStatus.CREATED,
    )
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 asset_bulk_upload(request):
    """
    Bulk upload many assets to add or modify
    """
    data = JSONParser().parse(request)
    if "import_csv" not in data:
        return JsonResponse(
            {
                "failure_message": Status.IMPORT_ERROR.value + BulkFailure.IMPORT.value,
                "errors": "Bulk upload request should have a parameter 'import_csv'",
            },
            status=HTTPStatus.BAD_REQUEST,
        )
    base_64_csv = data["import_csv"]
    csv_bytes_io = BytesIO(b64decode(re.sub(".*base64,", "", base_64_csv)))
    csv_string_io = StringIO(csv_bytes_io.read().decode("UTF-8-SIG"))
    csv_reader = csv.DictReader(csv_string_io)
    expected_fields = BulkAssetSerializer.Meta.fields
    given_fields = csv_reader.fieldnames
    if len(expected_fields) != len(given_fields) or set(  # check for repeated fields
        expected_fields
    ) != set(given_fields):
        return JsonResponse(
            {
                "failure_message": Status.IMPORT_ERROR.value
                + BulkFailure.IMPORT_COLUMNS.value
            },
            status=HTTPStatus.BAD_REQUEST,
        )
    bulk_asset_datas = []
    for row in csv_reader:
        bulk_asset_datas.append(dict(row))
    assets_to_add = []
    potential_modifications = []
    hostnames_in_import = set()
    asset_numbers_in_import = set()
    asset_datas = []
    chassis_asset_numbers = set()
    warning_message = ""
    for bulk_asset_data in bulk_asset_datas:
        asset_data = normalize_bulk_asset_data(bulk_asset_data)
        asset_datas.append(asset_data)
        try:
            model = ITModel.objects.get(
                vendor=asset_data["vendor"], model_number=asset_data["model_number"]
            )
        except ObjectDoesNotExist:
            failure_message = (
                Status.IMPORT_ERROR.value
                + "Model does not exist: "
                + "vendor="
                + asset_data["vendor"]
                + ", model_number="
                + asset_data["model_number"]
            )
            return JsonResponse(
                {"failure_message": failure_message}, status=HTTPStatus.BAD_REQUEST
            )
        if model.is_blade_chassis():
            if "asset_number" in asset_data and asset_data["asset_number"]:
                chassis_asset_numbers.add(asset_data["asset_number"])
        asset_data["model"] = model.id
        del asset_data["vendor"]
        del asset_data["model_number"]
        if asset_data["chassis_number"]:
            try:
                chassis = Asset.objects.get(asset_number=asset_data["chassis_number"])
                if not chassis.model.is_blade_chassis():
                    failure_message = (
                        Status.IMPORT_ERROR.value
                        + "Asset is not a chassis: "
                        + "asset_number="
                        + asset_data["chassis_number"]
                    )
                    return JsonResponse(
                        {"failure_message": failure_message},
                        status=HTTPStatus.BAD_REQUEST,
                    )
            except ObjectDoesNotExist:
                if not asset_data["chassis_number"] in chassis_asset_numbers:
                    failure_message = (
                        Status.IMPORT_ERROR.value
                        + "Chassis does not exist: "
                        + "asset_number="
                        + asset_data["chassis_number"]
                    )
                    return JsonResponse(
                        {"failure_message": failure_message},
                        status=HTTPStatus.BAD_REQUEST,
                    )
            else:
                asset_data["chassis"] = chassis.id
                del asset_data["chassis_number"]
        else:
            asset_data["chassis"] = None
            del asset_data["chassis_number"]
        if asset_data["datacenter"]:
            try:
                datacenter = Site.objects.get(abbreviation=asset_data["datacenter"])
            except ObjectDoesNotExist:
                failure_message = (
                    Status.IMPORT_ERROR.value
                    + "Provided datacenter doesn't exist: "
                    + asset_data["datacenter"]
                )
                return JsonResponse(
                    {"failure_message": failure_message}, status=HTTPStatus.BAD_REQUEST
                )
            if asset_data["rack"]:
                try:
                    row_letter = asset_data["rack"][:1].upper()
                    rack_num = asset_data["rack"][1:]
                    rack = Rack.objects.get(
                        datacenter=datacenter, row_letter=row_letter, rack_num=rack_num
                    )
                except ObjectDoesNotExist:
                    failure_message = (
                        Status.IMPORT_ERROR.value
                        + "Provided rack doesn't exist: "
                        + asset_data["rack"]
                    )
                    return JsonResponse(
                        {"failure_message": failure_message},
                        status=HTTPStatus.BAD_REQUEST,
                    )
                asset_data["rack"] = rack.id
            else:
                asset_data["rack"] = None
        if asset_data["datacenter"]:
            try:
                datacenter = Site.objects.get(abbreviation=asset_data["datacenter"])
            except ObjectDoesNotExist:
                failure_message = (
                    Status.IMPORT_ERROR.value
                    + "Provided datacenter doesn't exist: "
                    + asset_data["datacenter"]
                )
                return JsonResponse(
                    {"failure_message": failure_message}, status=HTTPStatus.BAD_REQUEST
                )
            else:
                asset_data["datacenter"] = datacenter.id
        else:
            asset_data["datacenter"] = None
        if asset_data["offline_site"]:
            try:
                offline_storage_site = Site.objects.get(
                    abbreviation=asset_data["offline_site"]
                )
            except ObjectDoesNotExist:
                failure_message = (
                    Status.IMPORT_ERROR.value
                    + "Provided offline storage site doesn't exist: "
                    + asset_data["offline_site"]
                )
                return JsonResponse(
                    {"failure_message": failure_message}, status=HTTPStatus.BAD_REQUEST
                )
            else:
                asset_data["offline_storage_site"] = offline_storage_site.id
        else:
            asset_data["offline_storage_site"] = None
        del asset_data["offline_site"]

        asset_serializer = AssetSerializer(data=asset_data)  # non-recursive to validate
        if not asset_serializer.is_valid():
            errors = asset_serializer.errors
            if not (
                # if the only errors are the asset number and/or
                # hostname uniqueness, that's fine - it's a modify
                (
                    len(errors.keys()) == 2  # known bug here!
                    and "hostname" in errors
                    and len(errors["hostname"]) == 1
                    and errors["hostname"][0].code == "unique"
                    and "asset_number" in errors
                    and len(errors["asset_number"]) == 1
                    and errors["asset_number"][0].code == "unique"
                )
                or (
                    len(errors.keys()) == 1
                    and "asset_number" in errors
                    and len(errors["asset_number"]) == 1
                    and errors["asset_number"][0].code == "unique"
                )
            ):
                return JsonResponse(
                    {
                        "failure_message": Status.IMPORT_ERROR.value
                        + BulkFailure.ASSET_INVALID.value
                        + parse_serializer_errors(asset_serializer.errors),
                        "errors": str(asset_serializer.errors),
                    },
                    status=HTTPStatus.BAD_REQUEST,
                )
            else:
                # HACKY FIX! There were validation errors with asset number and hostname but it's just because this is a modification. Let's try again
                asset_number = asset_data["asset_number"]
                del asset_data["asset_number"]
                hostname = asset_data["hostname"]
                del asset_data["hostname"]
                asset_serializer = AssetSerializer(data=asset_data)
                if not asset_serializer.is_valid():
                    return JsonResponse(
                        {
                            "failure_message": Status.IMPORT_ERROR.value
                            + BulkFailure.ASSET_INVALID.value
                            + parse_serializer_errors(asset_serializer.errors),
                            "errors": str(asset_serializer.errors),
                        },
                        status=HTTPStatus.BAD_REQUEST,
                    )
                else:
                    asset_serializer.validated_data["asset_number"] = asset_number
                    asset_serializer.validated_data["hostname"] = hostname
                    asset_data["asset_number"] = asset_number
                    asset_data["hostname"] = hostname
        try:
            validate_location_type(
                asset_serializer.validated_data["model"],
                asset_serializer.validated_data["rack"],
                asset_serializer.validated_data["rack_position"],
                asset_serializer.validated_data["chassis"],
                asset_serializer.validated_data["chassis_slot"],
                asset_serializer.validated_data["offline_storage_site"],
            )
        except ValidationError as error:
            return JsonResponse(
                {
                    "failure_message": Status.IMPORT_ERROR.value
                    + BulkFailure.ASSET_INVALID.value
                    + str(error.message)
                },
                status=HTTPStatus.BAD_REQUEST,
            )
        # Check that all hostnames in file are case insensitive unique
        if "hostname" in asset_data and asset_data["hostname"]:
            asset_data_hostname_lower = asset_data["hostname"].lower()
            if asset_data_hostname_lower in hostnames_in_import:
                failure_message = (
                    Status.IMPORT_ERROR.value
                    + "Hostname must be unique, but '"
                    + asset_data_hostname_lower
                    + "' appears more than once in import. "
                )
                return JsonResponse(
                    {"failure_message": failure_message}, status=HTTPStatus.BAD_REQUEST
                )
            else:
                hostnames_in_import.add(asset_data_hostname_lower)
        # Check that all asset_numbers in file are unique
        if "asset_number" in asset_data and asset_data["asset_number"]:
            asset_number = asset_data["asset_number"]
            if asset_number in asset_numbers_in_import:
                failure_message = (
                    Status.IMPORT_ERROR.value
                    + "Asset number must be unique, but '"
                    + str(asset_number)
                    + "' appears more than once in import. "
                )
                return JsonResponse(
                    {"failure_message": failure_message}, status=HTTPStatus.BAD_REQUEST
                )
            else:
                asset_numbers_in_import.add(asset_number)
        asset_exists = False
        if "asset_number" in asset_data and asset_data["asset_number"]:
            try:
                existing_asset = Asset.objects.get(
                    asset_number=asset_data["asset_number"]
                )
            except ObjectDoesNotExist:
                pass
            else:
                asset_exists = True
        if asset_exists:
            # asset number specfies existing asset
            try:
                validate_user_permission_on_new_asset_data(
                    request.user, asset_data, data_is_validated=False
                )
            except UserAssetPermissionException as auth_error:
                return JsonResponse(
                    {"failure_message": Status.IMPORT_ERROR.value + str(auth_error)},
                    status=HTTPStatus.BAD_REQUEST,
                )
            try:
                validate_location_modification(asset_data, existing_asset)
            except Exception as error:
                failure_message = (
                    Status.IMPORT_ERROR.value
                    + "Asset "
                    + str(asset_data["asset_number"])
                    + " would conflict location with an existing asset. "
                )
                return JsonResponse(
                    {"failure_message": failure_message, "errors": str(error)},
                    status=HTTPStatus.BAD_REQUEST,
                )
            potential_modifications.append(
                {"existing_asset": existing_asset, "new_data": asset_data}
            )
        else:
            # asset number not provided or it is new
            if (
                "rack" in asset_serializer.validated_data
                and asset_serializer.validated_data["rack"]
            ):
                site = asset_serializer.validated_data["rack"].datacenter
            elif (
                "chassis" in asset_serializer.validated_data
                and asset_serializer.validated_data["chassis"]
                and asset_serializer.validated_data["chassis"].rack
            ):
                site = asset_serializer.validated_data["chassis"].rack.datacenter
            elif (
                "chassis" in asset_serializer.validated_data
                and asset_serializer.validated_data["chassis"]
                and asset_serializer.validated_data["chassis"].offline_storage_site
            ):
                site = asset_serializer.validated_data["chassis"].offline_storage_site
            elif (
                "offline_storage_site" in asset_serializer.validated_data
                and asset_serializer.validated_data["offline_storage_site"]
            ):
                site = asset_serializer.validated_data["offline_storage_site"]
            if not user_has_asset_permission(request.user, site):
                return JsonResponse(
                    {
                        "failure_message": Status.AUTH_ERROR.value
                        + AuthFailure.ASSET.value,
                        "errors": "User "
                        + request.user.username
                        + " does not have asset permission in site id="
                        + str(site.id),
                    },
                    status=HTTPStatus.UNAUTHORIZED,
                )
            model = ITModel.objects.get(id=asset_data["model"])
            try:
                if (
                    "rack" in asset_serializer.validated_data
                    and asset_serializer.validated_data["rack"]
                ):
                    validate_asset_location_in_rack(
                        asset_serializer.validated_data["rack"].id,
                        asset_serializer.validated_data["rack_position"],
                        model.height,
                        asset_id=None,
                    )
                elif (
                    "chassis" in asset_serializer.validated_data
                    and asset_serializer.validated_data["chassis"]
                ):
                    validate_asset_location_in_chassis(
                        asset_serializer.validated_data["chassis"].id,
                        asset_serializer.validated_data["chassis_slot"],
                    )
            except LocationException as error:
                if "asset_number" in asset_data and asset_data["asset_number"]:
                    asset_name = str(asset_data["asset_number"])
                elif "hostname" in asset_data and asset_data["hostname"]:
                    asset_name = asset_data["hostname"]
                else:
                    asset_name = ""
                return JsonResponse(
                    {
                        "failure_message": Status.IMPORT_ERROR.value
                        + "Asset "
                        + asset_name
                        + " is invalid. "
                        + str(error)
                    },
                    status=HTTPStatus.BAD_REQUEST,
                )
            else:
                assets_to_add.append(
                    {"asset_serializer": asset_serializer, "asset_data": asset_data}
                )
    try:
        no_infile_location_conflicts(asset_datas)
    except LocationException as error:
        failure_message = (
            Status.IMPORT_ERROR.value
            + "Location conflicts among assets in import file. "
            + str(error)
        )
        return JsonResponse(
            {"failure_message": failure_message}, status=HTTPStatus.BAD_REQUEST
        )
    records_added = 0
    for asset_to_add in assets_to_add:
        records_added += 1
        asset_serializer = asset_to_add["asset_serializer"]
        asset_data = asset_to_add["asset_data"]
        if "chassis_number" in asset_data:
            chassis = Asset.objects.get(asset_number=asset_data["chassis_number"])
            asset_serializer.validated_data["chassis"] = chassis
            asset_data["chassis"] = chassis.id
            del asset_data["chassis_number"]
        asset_added = asset_serializer.save()
        try:
            save_power_connections(asset_data=asset_data, asset_id=asset_added.id)
        except PowerConnectionException as error:
            warning_message += "Some power connections couldn't be saved. " + str(error)
    records_ignored = 0
    modifications_to_approve = []
    for potential_modification in potential_modifications:
        new_data = potential_modification["new_data"]
        new_data["model"] = ITModelSerializer(
            ITModel.objects.get(id=new_data["model"])
        ).data
        if new_data["rack"]:
            new_data["rack"] = RackSerializer(
                Rack.objects.get(id=new_data["rack"])
            ).data
        if new_data["chassis"]:
            new_data["chassis"] = ChassisSerializer(
                Asset.objects.get(id=new_data["chassis"])
            ).data
        if new_data["datacenter"]:
            new_data["datacenter"] = SiteSerializer(
                Site.objects.get(id=new_data["datacenter"])
            ).data
        if new_data["offline_storage_site"]:
            new_data["offline_storage_site"] = SiteSerializer(
                Site.objects.get(id=new_data["offline_storage_site"])
            ).data
        existing_data = RecursiveAssetSerializer(
            potential_modification["existing_asset"]
        ).data
        # macs and connections aren't specified in this file, so ignore them
        del existing_data["mac_addresses"]
        del existing_data["network_connections"]
        del existing_data["network_graph"]
        del existing_data["blades"]
        if records_are_identical(existing_data, new_data):
            records_ignored += 1
        else:
            new_data["id"] = existing_data["id"]
            for field in existing_data.keys():
                if field not in new_data:
                    new_data[field] = None
            modifications_to_approve.append(
                {"existing": existing_data, "modified": new_data}
            )
    response = {
        "added": records_added,
        "ignored": records_ignored,
        "modifications": modifications_to_approve,
    }
    if warning_message:
        response["warning_message"] = warning_message
    log_bulk_upload(
        request.user,
        ElementType.ASSET,
        records_added,
        records_ignored,
        len(modifications_to_approve),
    )
    return JsonResponse(response, status=HTTPStatus.OK)
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,
        )
Exemple #7
0
def rack_create(request):
    """
    Create racks within specified range.
    """
    range_serializer = RackRangeSerializer(data=request.data)
    if not range_serializer.is_valid():
        return JsonResponse(
            {
                "failure_message":
                Status.INVALID_INPUT.value +
                parse_serializer_errors(range_serializer.errors),
                "errors":
                str(range_serializer.errors),
            },
            status=HTTPStatus.BAD_REQUEST,
        )
    datacenter_id = range_serializer.get_datacenter()
    if not user_has_asset_permission(request.user, datacenter_id):
        return JsonResponse(
            {
                "failure_message":
                Status.AUTH_ERROR.value + AuthFailure.RACK.value,
                "errors":
                "User " + request.user.username +
                " does not have asset permission in datacenter id=" +
                str(datacenter_id),
            },
            status=HTTPStatus.UNAUTHORIZED,
        )
    racks = Rack.objects.filter(
        datacenter=range_serializer.get_datacenter(),
        rack_num__range=range_serializer.get_number_range(),  # inclusive range
        row_letter__range=range_serializer.get_row_range(),
    )
    if racks.count() > 0:
        return JsonResponse(
            {
                "failure_message":
                Status.CREATE_ERROR.value +
                get_rack_failure_message(range_serializer, "created") +
                get_rack_exist_failure(racks)
            },
            status=HTTPStatus.BAD_REQUEST,
        )
    rack_row_list = range_serializer.get_row_list()
    rack_num_list = range_serializer.get_number_list()
    for row in rack_row_list:
        for num in rack_num_list:
            rack = Rack(
                datacenter=range_serializer.get_datacenter(),
                row_letter=row,
                rack_num=num,
            )
            rack.save()
    related_racks = range_serializer.get_range_as_string()
    log_rack_action(
        request.user,
        Action.CREATE,
        related_racks,
        range_serializer.get_datacenter().abbreviation,
    )
    return JsonResponse(
        {
            "success_message":
            Status.SUCCESS.value + "Racks " + related_racks +
            " were created in datacenter " +
            range_serializer.get_datacenter().abbreviation
        },
        status=HTTPStatus.OK,
    )
Exemple #8
0
def rack_delete(request):
    """
    Delete racks within specified range.
    """
    range_serializer = RackRangeSerializer(data=request.data)
    if not range_serializer.is_valid():
        return JsonResponse(
            {
                "failure_message":
                Status.INVALID_INPUT.value +
                parse_serializer_errors(range_serializer.errors),
                "errors":
                str(range_serializer.errors),
            },
            status=HTTPStatus.BAD_REQUEST,
        )
    datacenter_id = range_serializer.get_datacenter()
    if not user_has_asset_permission(request.user, datacenter_id):
        return JsonResponse(
            {
                "failure_message":
                Status.AUTH_ERROR.value + AuthFailure.RACK.value,
                "errors":
                "User " + request.user.username +
                " does not have asset permission in datacenter id=" +
                str(datacenter_id),
            },
            status=HTTPStatus.UNAUTHORIZED,
        )
    nonexistent_rack_names = []
    unempty_racks = []
    for row_letter in range_serializer.get_row_list():
        for rack_num in range_serializer.get_number_list():
            try:
                rack = Rack.objects.get(
                    datacenter=range_serializer.get_datacenter(),
                    row_letter=row_letter,
                    rack_num=rack_num,
                )
            except ObjectDoesNotExist:
                nonexistent_rack_names.append(row_letter + str(rack_num))
            else:
                if Asset.objects.filter(rack=rack.id).count() > 0:
                    unempty_racks.append(rack)
    if len(unempty_racks) > 0:
        return JsonResponse(
            {
                "failure_message":
                Status.DELETE_ERROR.value +
                get_rack_failure_message(range_serializer, "deleted") +
                get_rack_with_asset_failure(unempty_racks)
            },
            status=HTTPStatus.BAD_REQUEST,
        )
    if len(nonexistent_rack_names) > 0:
        return JsonResponse(
            {
                "failure_message":
                Status.DELETE_ERROR.value +
                get_rack_failure_message(range_serializer, "deleted") +
                get_rack_do_not_exist_failure(nonexistent_rack_names)
            },
            status=HTTPStatus.BAD_REQUEST,
        )
    racks = Rack.objects.filter(
        datacenter=range_serializer.get_datacenter(),
        rack_num__range=range_serializer.get_number_range(),  # inclusive range
        row_letter__range=range_serializer.get_row_range(),
    )
    try:
        racks.delete()
    except Exception as error:
        return JsonResponse(
            {
                "failure_message":
                Status.DELETE_ERROR.value + "Rack(s)" +
                GenericFailure.ON_DELETE.value,
                "errors":
                str(error),
            },
            status=HTTPStatus.BAD_REQUEST,
        )
    related_racks = range_serializer.get_range_as_string()
    log_rack_action(
        request.user,
        Action.DELETE,
        related_racks,
        range_serializer.get_datacenter().abbreviation,
    )
    return JsonResponse(
        {
            "success_message":
            Status.SUCCESS.value + "Racks " + related_racks +
            " were deleted in datacenter" +
            range_serializer.get_datacenter().abbreviation
        },
        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,
        )