Server Reuse

PowerBI with embedded PowerApps enabling customers to reserve Servers coming out of Azure

Cole Russell
June 20, 2022

Solution Description

The Server Reuse Power Platform solution begins with a Kusto query that feeds a PowerBi Dataset, capturing the latest Servers slated for Decommission. This Dataset is then used to produce a PowerBI Report with an embedded Canvas PowerApp. The User can select assets displayed by the PowerBI Report which are then passed to the Canvas App, allowing the User to verify their selection before they reserve the assets. The User then chooses “Reserve Servers” where the Reservations details are passed to Dataverse tables and the User then receives an email confirmation of their selection.

E2E Diagram

Server_Reuse_Figma

Impact

At the time of writing this post, over 1600 servers have been reused through the portal accounting for $16M in savings and 630 mtCO2e carbon emissions reduced!

Reservation Portal

Test Reservation Portal Server_Reuse_Reservation_Portal

Test Reservation Portal with Servers Selected Server_Reuse_Reservation_Selection

Test Reservation Management Portal Server_Reuse_Reservation_Management

Reservation Code

The PowerFX reservation code performs several actions “OnSubmit” of the Reservation Button:

  1. Collect all filtered PowerBI Data passed to the App.
  2. Determine last Reservation # and increment the variable by 1.
  3. Patch 3 variations of data to 3 Dataverse tables that have relationships.
  4. Perform error checking against the Reservation Table and notify User if Successful.
  5. Refresh the PowerBI Data (PowerBIIntegration.Refresh()).
  6. Display Reservation Popup to User showing Details.
// Create Collection from PowerBIIntegration.Data//
ClearCollect(
    colPowerBIData,
    PowerBIIntegration.Data
);
// Set Reservation Number to be Max of all Reservation Numbers //
Set(
    varResNumber,
    Max(
        Reservations,
        ReservationNumber
    ) +1
);

// Push Reservation Asset Details to Dataverse table ReservationAssetDetails //
ForAll(
    colPowerBIData,
    Patch(
        ReservationAssetDetails,
        Defaults(ReservationAssetDetails),
        {
            cscs_name: ThisRecord.AssetTag,
            cscs_assettag: ThisRecord.AssetTag,
            cscs_decommunitid: ThisRecord.DecommUnitId,
            cscs_serialnumber: ThisRecord.SerialNumber,
            cscs_securityclassification: ThisRecord.SecurityClassification
        }
    )
);

// Push Reservation Details to Dataverse table ReservationAssets //
ForAll(
    colPowerBIData,
    Patch(
        ReservationAssets,
        Defaults(ReservationAssets),
        {
            cscs_name: ThisRecord.ProjectId,
            cscs_reservationnumber: Text(varResNumber),
            cscs_projectid: ThisRecord.ProjectId,
            cscs_decommunitid: ThisRecord.DecommUnitId,
            cscs_financialskuid: ThisRecord.FinancialSkuId,
            cscs_sku: ThisRecord.SKU,
            cscs_rackid: ThisRecord.RackId,
            cscs_rackname:ThisRecord.RackName
        }
    )
);

// Push Reservation Details to Dataverse table Reservations and link to ReservationAssets//
Patch(
    Reservations,
    Defaults(Reservations),
    {
        cscs_name:varResNumber,
        cscs_reservationnumber: varResNumber,
        cscs_customercontact: Concat(
            ForAll(
                ComboBox_CustomerContact.SelectedItems,
                Mail
            ),
            Value,
            ";"
        ),
        cscs_dccode: First(colPowerBIData).DcCode,
        cscs_destination: First(ComboBox_Dest.SelectedItems).Destination,
        cscs_eg: First(colPowerBIData).EG,
        cscs_email: User().Email,
        cscs_executionphase: First(colPowerBIData).ExecutionPhase,
        cscs_financeio: Value(TextInput_FinanIO.Text),
        cscs_needbydate: DatePicker_NeedByDate.SelectedDate,
        cscs_pg: First(ComboBox_PG.SelectedItems).PG,
        cscs_projectedldend: First(colPowerBIData).ProjectedLDEnd,
        cscs_projectid: First(colPowerBIData).ProjectId,
        cscs_reservationnotes: TextReservationInput.Text,
        cscs_unittype: First(colPowerBIData).UnitType,
        cscs_user: User().FullName,
        cscs_physicaldecommemail:"no"
    }
);
If(
     // check if there were any errors when the test score was submitted
    !IsEmpty(Errors(Reservations)),
     // if true, show any error message
    Notify(
        Concat(
            Errors(Reservations),
            Column & ": " & Message
        ),
        NotificationType.Error
    ),
     // else, go to success screen
    Notify(
        "Reservation Successful!",
        NotificationType.Success
    )
);
// Refresh PowerBI Data to remove reservation from Gallery //
PowerBIIntegration.Refresh();
// Update Popup to True //
UpdateContext({ReservedPopup: true});