Appearance
Starter Models Repository
Introduction
To execute a simulation and generate a result, Zypr requires a Pool Resource Model (PRM). A "pool" represents a collection of servers, which are similarly configured (including the software stack) and hosts one or many workloads. The model describes this resource collection, its current resource state, and your assumptions about what factors influence how pool resources might evolve over time.
A PRM is defined in JSON. You define a PRM and save it to your local directory - not in Zypr. To execute a simulation, use the POST Simulations endpoint, which returns the Scenario response object. If your simulation completes successfully, the ResourceRequirementsForecast object is populated and included in the Scenario object. The ResourceRequirementsForecast object contains time-series data for hardware, software, power and space consumption, inventory balances, server turnover, and key statistics.
The Pool Resource Model Repository contains "starter" models to assist you in defining valid PRMs that best meet your particular forecasting needs. The models below are organized by common use-cases.
Important Reminder
All repository models contain values that should be considered arbitrary and not intended to reflect your technical environment, cost structure, or expectation of future events.
Models are provided solely to demonstrate common use cases, and how to utilize Zypr objects to describe scenarios that are relevant to your organization.
Your PRM should reflect your data, assumptions, and expectations.
Pool Models by Use Case
Base Model A
This model contains pre-defined objects in which the hardware transactional lot unit is a server. Use this model as a base in which to add jump events, constraints, and more complex software license terms using the CostRules and ConsumptionRules objects.
This model will not pass validation; it is missing at least one Jump Event in the Jump Event array.
Key Objects
- Settings
- SimulationRules
- EvolutionRules
- NewServerConfiguration
- PowerConsumptionTerms
- FacilityConsumptionTerms
- ValuationRules
- SoftwareResources
- ServerInventory
json
"Settings": {
"ScenarioName": "Basic Model Definition",
"ModelEffectiveDate": "2023-01-01",
"DataValidationCascadeMode": "Stop",
"EmailResults": true,
"Pool": {
"Id": "Your unique id",
"Name": "Name of pool",
"Description": "Long description of pool"
}
},
"SimulationRules": {
"SimulationCostScope": "All",
"SimulationType": "Optimal",
"ScenarioDuration": 6.0,
"FindSolutionByMetric": "TotalCumulativeCostPerYear",
"ServerReplacementTime": null
},
"EvolutionRules": {
"PoolUtilizationPercentCurrent": 62.5,
"PoolUtilizationBoundaryPercentLower": 60.0,
"PoolUtilizationBoundaryPercentUpper": 65.0,
"ServiceDemandGrowthPercent": 25,
"InventoryQueueBias": "Auto"
},
"NewServerConfiguration": {
"ServerPerf": 560,
"ServerCost": 12000,
"ServerWatts": 415,
"ProcessorSetSize": 2,
"CoreSetSize": 32,
"ServerSize": 2
},
"PowerConsumptionTerms": {
"PoolPowerDrawPercent": 80,
"DatacenterPowerkWhCostRate": 0.115,
"DatacenterPUE": 1.4,
"PowerCostInflationPercent": 2.5
},
"FacilityConsumptionTerms": {
"DatacenterDefault": true,
"PowerConsumptionMarkupPercent": 0,
"ServerSize": 1,
"ServerSizeUnitCost": 65,
"FacilityFeeInflationPercent": 2.75
},
"ValuationRules": {
"DiscountPercent": 6.5,
"IncludeServerResidualValue": true,
"ResidualValueBidAskSpreadPercent": 40,
"InitialInventoryIsNew": false
},
"SoftwareResources": {
"PoolSoftwareStack": [
1,
2
],
"SoftwareInventoryTerms": [
{
"LicenseId": 1,
"LicenseMetric": "Processor",
"LicenseClass": "Perpetual",
"ContractType": "Coterminous",
"ContractTerms": {
"AnniversaryDate": "2024-10-31",
"TermLength": 3,
"CreateSettlementCalendar": "Union",
"RenewalSchedule": "Contract",
"AttemptPositionReset": false,
"CostRules": []
},
"Fee": 2000,
"PerpetualSupportPercent": 25,
"InitialPosition": null
},
{
"LicenseId": 2,
"LicenseMetric": "Processor",
"LicenseClass": "Subscription",
"ContractType": "Coterminous",
"ContractTerms": {
"AnniversaryDate": "2025-03-31",
"TermLength": 3,
"TrueUpMonth": 6,
"CreateSettlementCalendar": "Custom",
"RenewalSchedule" : "TrueUp",
"AttemptPositionReset": false,
"CostRules": []
},
"Fee": 4000,
"InitialPosition": null
},
{
"LicenseId": 3,
"LicenseMetric": "Processor",
"LicenseClass": "Subscription",
"ContractType": "Instance",
"Fee": 500
}
]
},
"ServerInventory": [
{
"ServerQty": 20,
"ServerPerf": 100,
"ServerWatts": 425,
"ProcessorSetSize": 2,
"CoreSetSize": 8,
"InitialAge": 4.8,
"ServerSize": 2
},
{
"ServerQty": 20,
"ServerPerf": 135,
"ServerWatts": 425,
"ProcessorSetSize": 2,
"CoreSetSize": 10,
"InitialAge": 4.2,
"ServerSize": 2
},
{
"ServerQty": 20,
"ServerPerf": 150,
"ServerWatts": 425,
"ProcessorSetSize": 2,
"CoreSetSize": 12,
"InitialAge": 3.6,
"ServerSize": 2
},
{
"ServerQty": 22,
"ServerPerf": 160,
"ServerWatts": 400,
"ProcessorSetSize": 2,
"CoreSetSize": 8,
"InitialAge": 3.2,
"ServerSize": 2
},
{
"ServerQty": 20,
"ServerPerf": 240,
"ServerWatts": 400,
"ProcessorSetSize": 2,
"CoreSetSize": 12,
"InitialAge": 2.6,
"ServerSize": 2
},
{
"ServerQty": 16,
"ServerPerf": 360,
"ServerWatts": 400,
"ProcessorSetSize": 2,
"CoreSetSize": 20,
"InitialAge": 2.0,
"ServerSize": 2
},
{
"ServerQty": 18,
"ServerPerf": 430,
"ServerWatts": 400,
"ProcessorSetSize": 2,
"CoreSetSize": 24,
"InitialAge": 1.4,
"ServerSize": 2
},
{
"ServerQty": 20,
"ServerPerf": 515,
"ServerWatts": 415,
"ProcessorSetSize": 2,
"CoreSetSize": 28,
"InitialAge": 0.8,
"ServerSize": 2
},
{
"ServerQty": 18,
"ServerPerf": 560,
"ServerWatts": 415,
"ProcessorSetSize": 2,
"CoreSetSize": 32,
"InitialAge": 0.2,
"ServerSize": 2
}
],
"JumpEvents":[],
"Constraints":[]
}
Notes
This model's utilization boundaries and service demand growth percentage sets capacity additions to the pool approximately every four months.
This model includes server inventory definitions and a software stack containing two software items. The server inventory objects all contain predefined values for chronological InitialAge.
The chronological age of a server is not used to to determine add/remove transactions when the SimulationType property is set to 'Optimal'. Chronological age is used in several age-based output calculations.
Chronological InitialAge value is required when the SimulationType property is set to 'Fixed'.
Base Model B
This model contains pre-defined objects in which the hardware transactional lot unit is a rack. Use this model as a base in which to add jump events, constraints, and more complex software license terms using the CostRules and ConsumptionRules objects.
This model will not pass validation; it is missing at least one Jump Event in the Jump Event array.
Key Objects
- Settings
- SimulationRules
- EvolutionRules
- NewServerConfiguration
- PowerConsumptionTerms
- FacilityConsumptionTerms
- ValuationRules
- SoftwareResources
- ServerInventory
json
"Settings": {
"ScenarioName": "Basic Model Definition",
"ModelEffectiveDate": "2023-01-01",
"DataValidationCascadeMode": "Stop",
"EmailResults": true,
"Pool": {
"Id": "Your unique id",
"Name": "Name of pool",
"Description": "Long description of pool"
}
},
"SimulationRules": {
"SimulationCostScope": "All",
"SimulationType": "Optimal",
"ScenarioDuration": 6.0,
"FindSolutionByMetric": "TotalCumulativeCostPerYear",
"ServerReplacementTime": null
},
"EvolutionRules": {
"PoolUtilizationPercentCurrent": 62.5,
"PoolUtilizationBoundaryPercentLower": 60.0,
"PoolUtilizationBoundaryPercentUpper": 65.0,
"ServiceDemandGrowthPercent": 25,
"InventoryQueueBias": "Auto",
"LotUnit": "Rack"
},
"NewServerConfiguration": {
"RackSize": 42,
"RackServerQty": 21,
"RackCost": 252000,
"ServerPerf": 560,
"ServerWatts": 415,
"ProcessorSetSize": 2,
"CoreSetSize": 32,
"ServerSize": 2
},
"PowerConsumptionTerms": {
"PoolPowerDrawPercent": 80,
"DatacenterPowerkWhCostRate": 0.115,
"DatacenterPUE": 1.4,
"PowerCostInflationPercent": 2.5
},
"FacilityConsumptionTerms": {
"DatacenterDefault": true,
"PowerConsumptionMarkupPercent": 0,
"ServerSize": 1,
"ServerSizeUnitCost": 65,
"FacilityFeeInflationPercent": 2.75
},
"ValuationRules": {
"DiscountPercent": 6.5,
"IncludeServerResidualValue": true,
"ResidualValueBidAskSpreadPercent": 40,
"InitialInventoryIsNew": false
},
"SoftwareResources": {
"PoolSoftwareStack": [
1,
2
],
"SoftwareInventoryTerms": [
{
"LicenseId": 1,
"LicenseMetric": "Processor",
"LicenseClass": "Perpetual",
"ContractType": "Coterminous",
"ContractTerms": {
"AnniversaryDate": "2024-10-31",
"TermLength": 3,
"CreateSettlementCalendar": "Union",
"RenewalSchedule": "Contract",
"AttemptPositionReset": false,
"CostRules": []
},
"Fee": 2000,
"PerpetualSupportPercent": 25,
"InitialPosition": null
},
{
"LicenseId": 2,
"LicenseMetric": "Processor",
"LicenseClass": "Subscription",
"ContractType": "Coterminous",
"ContractTerms": {
"AnniversaryDate": "2025-03-31",
"TermLength": 3,
"TrueUpMonth": 6,
"CreateSettlementCalendar": "Custom",
"RenewalSchedule" : "TrueUp",
"AttemptPositionReset": false,
"CostRules": []
},
"Fee": 4000,
"InitialPosition": null
},
{
"LicenseId": 3,
"LicenseMetric": "Processor",
"LicenseClass": "Subscription",
"ContractType": "Instance",
"Fee": 500
}
]
},
"ServerInventory": [
{
"RackQty": 20,
"RackSize": 42,
"RackServerQty": 21,
"ServerPerf": 100,
"ServerWatts": 425,
"ProcessorSetSize": 2,
"CoreSetSize": 8,
"InitialAge": 4.8,
"ServerSize": 2
},
{
"RackQty": 20,
"RackSize": 42,
"RackServerQty": 21,
"ServerPerf": 135,
"ServerWatts": 425,
"ProcessorSetSize": 2,
"CoreSetSize": 10,
"InitialAge": 4.2,
"ServerSize": 2
},
{
"RackQty": 20,
"RackSize": 42,
"RackServerQty": 21,
"ServerPerf": 150,
"ServerWatts": 425,
"ProcessorSetSize": 2,
"CoreSetSize": 12,
"InitialAge": 3.6,
"ServerSize": 2
},
{
"RackQty": 22,
"RackSize": 42,
"RackServerQty": 21,
"ServerPerf": 160,
"ServerWatts": 400,
"ProcessorSetSize": 2,
"CoreSetSize": 8,
"InitialAge": 3.2,
"ServerSize": 2
},
{
"RackQty": 20,
"RackSize": 42,
"RackServerQty": 21,
"ServerPerf": 240,
"ServerWatts": 400,
"ProcessorSetSize": 2,
"CoreSetSize": 12,
"InitialAge": 2.6,
"ServerSize": 2
},
{
"RackQty": 16,
"RackSize": 42,
"RackServerQty": 21,
"ServerPerf": 360,
"ServerWatts": 400,
"ProcessorSetSize": 2,
"CoreSetSize": 20,
"InitialAge": 2.0,
"ServerSize": 2
},
{
"RackQty": 18,
"RackSize": 42,
"RackServerQty": 21,
"ServerPerf": 430,
"ServerWatts": 400,
"ProcessorSetSize": 2,
"CoreSetSize": 24,
"InitialAge": 1.4,
"ServerSize": 2
},
{
"RackQty": 20,
"RackSize": 42,
"RackServerQty": 21,
"ServerPerf": 515,
"ServerWatts": 415,
"ProcessorSetSize": 2,
"CoreSetSize": 28,
"InitialAge": 0.8,
"ServerSize": 2
},
{
"RackQty": 18,
"RackSize": 42,
"RackServerQty": 21,
"ServerPerf": 560,
"ServerWatts": 415,
"ProcessorSetSize": 2,
"CoreSetSize": 32,
"InitialAge": 0.2,
"ServerSize": 2
}
],
"JumpEvents":[],
"Constraints":[]
}
Notes
This model's utilization boundaries and service demand growth percentage sets capacity additions to the pool approximately every four months.
This model includes rack inventory definitions and software stack containing two software items. The rack inventory objects all contain predefined values for chronological InitialAge.
The chronological age of a rack is not used to to determine add/remove transactions when the SimulationType property is set to 'Optimal'. Chronological age is used in several age-based output calculations.
Chronological InitialAge value is required when the SimulationType property is set to 'Fixed'.
Modify server config & performance
These jump events define configuration and performance changes at 1.5 years and 3.5 years.
May be used with Base Model A only.
Key Objects
- NewServerConfiguration
- Configuration Jump Event
- Performance Jump Event
Repository Lookup Codes
Code | Version |
---|---|
P01 | 1.0 |
json
"JumpEvents": [
{
"EventId": "1",
"EventType": "Configuration",
"TriggerTime": 1.5,
"ServerWatts": 420,
"ProcessorSetSize": 2,
"CoreSetSize": 48,
"ServerCost": 14000,
"ServerSize": 2
},
{
"EventId": "2",
"EventType": "Performance",
"PerformanceType": "Server",
"TriggerTime": 1.5,
"PerformanceJumpPercent": 88.6
},
{
"EventId": "3",
"EventType": "Configuration",
"TriggerTime": 3.5,
"ServerWatts": 450,
"ProcessorSetSize": 2,
"CoreSetSize": 64,
"ServerCost": 15000,
"ServerSize": 2
},
{
"EventId": "4",
"EventType": "Performance",
"PerformanceType": "Server",
"TriggerTime": 3.5,
"PerformanceJumpPercent": 66.7
}
]
Notes
The Configuration jump event modifies all properties of the NewServerConfiguration object, at the jump event's trigger time, except the ServerPerf property, which is modified using the Performance jump event object.
The Performance jump event modifies the scalar rating of the NewServerConfiguration object by applying the PerformanceJumpPercent property value to the ServerPerf property value at the trigger time of the jump event.
For example, in Base Model A, the ServerPerf property value is 560. In jump event #2, the PerformanceJumpPercent property value of 88.6% is applied to 560, results in 1056.16, and updates the ServerPerf property to the rounded value of 1056. In jump event #4, the PerformanceJumpPercent property value is 66.7%, which is applied to then current ServerPerf property value of 1056, results in 1760.35. The ServerPerf property is updated to the rounded value of 1760.
'Server' vs 'Pool' Performance Types
The above example demonstrates how to apply a change in server performance to the NewServerConfiguration object, which only applies to server additions to the pool.
Alternatively, a PerformanceType property set to 'Pool' modifies the ServerPerf property value of all existing server inventory and the NewServerConfiguration object.
Modify rack config & performance
These jump events define configuration and performance changes at 1.5 years and 3.5 years.
May be used with Base Model B only.
INFO
The performance jump event modifies the performance rating of a server that is defined in the NewServerConfiguration object, and calculates the performance rating of the Rack by summing the ServerPerf property of each server in the rack.
Key Objects
- NewServerConfiguration
- Configuration Jump Event
- Performance Jump Event
Repository Lookup Codes
Code | Version |
---|---|
P02 | 1.0 |
json
"JumpEvents": [
{
"EventId": "1",
"EventType": "Configuration",
"TriggerTime": 1.5,
"RackSize": 42,
"RackServerQty": 21,
"RackCost": 294000,
"ServerWatts": 420,
"ProcessorSetSize": 2,
"CoreSetSize": 48,
"ServerSize": 2
},
{
"EventId": "2",
"EventType": "Performance",
"PerformanceType": "Server",
"TriggerTime": 1.5,
"PerformanceJumpPercent": 88.6
},
{
"EventId": "3",
"EventType": "Configuration",
"TriggerTime": 3.5,
"RackSize": 42,
"RackServerQty": 21,
"RackCost": 315000,
"ServerWatts": 450,
"ProcessorSetSize": 2,
"CoreSetSize": 64,
"ServerSize": 2
},
{
"EventId": "4",
"EventType": "Performance",
"PerformanceType": "Server",
"TriggerTime": 3.5,
"PerformanceJumpPercent": 66.7
}
]
Notes
The Configuration jump event modifies all properties of the NewServerConfiguration object including the Rack-based properties, at the jump event's trigger time, except the ServerPerf property, which is modified using the Performance jump event object.
The Performance jump events are the same as specified in the "Modify server config & performance" example.
In this example, the rack size and rack server quantity (i.e., server quantity within a rack) are not changed from what is defined in Base Model B. The server configuration changes are the same as specified in the "Modify server config & performance" example.
Increase pool performance rating
This code block modifies server perf for the entire pool.
This jump event may be added to either Base Model A or B.
Key Objects
- ServerInventory
- NewServerConfiguration
- Performance Jump Event
Repository Lookup Codes
Code | Version |
---|---|
P03 | 1.0 |
json
"JumpEvents": [
{
"EventId": "1",
"EventType": "Performance",
"PerformanceType": "Pool",
"TriggerTime": 0.5,
"PerformanceJumpPercent": 5
}
]
Notes
In the example above, the PerformanceType property value of "Pool" triggers an increase of 5% to the ServerPerf property value of all existing server inventory and the NewServerConfiguration object.
For example, re-rating the performance of an entire pool may be due to a network upgrade that significantly reduces I/O wait time of pool CPUs.
Modify service demand growth percentage
This code block changes the service demand growth percentage at a future time.
This jump event may be added to either Base Model A or B.
Key Objects
- EvolutionRules
- Demand Jump Event
Repository Lookup Codes
Code | Version |
---|---|
D01 | 1.0 |
json
"JumpEvents": [
{
"EventId": "1",
"EventType": "Demand",
"DemandType": "GrowthPercent",
"TriggerTime": 1.25,
"DemandPercent": 30
}
]
Notes
The Demand Jump Event DemandType property with value 'GrowthPercent" modifies the ServiceDemandGrowthPercent property value to 30 at trigger time 1.25 years. The DemandPercent property value represents an absolute value that replaces the value of the ServiceDemandGrowthPercent property in the EvolutionRules object.
The DemandPercent property value must be a positive number. A simulation cannot be evolved, over time, based on a negative demand percentage (e.g., -10).
Add absolute service demand
This code block adds a permanent increase in absolute service demand at a future time.
This jump event may be added to either Base Model A or B.
Key Objects
- Demand Jump Event
Repository Lookup Codes
Code | Version |
---|---|
D02 | 1.0 |
json
"JumpEvents": [
{
"EventId": "1",
"EventType": "Demand",
"DemandType": "AbsPermanent",
"TriggerTime": 1.25,
"DemandPercent": 15
}
]
Notes
The Demand Jump Event DemandType property with value 'AbsPermanent" will increase absolute demand by 15% at 1.25 years. This is a onetime modification and does not modify the ServiceDemandGrowthPercent property in the EvolutionRules object.
The DemandPercent property value represents a relative change that is applied to current absolute demand at the selected trigger time. This value may be positive or negative. A value of zero will fail validation.
Add transitory service demand
This code block adds a transitory increase in absolute service demand at a future time.
This jump event may be added to either Base Model A or B.
Key Objects
- Demand Jump Event
Repository Lookup Codes
Code | Version |
---|---|
D03 | 1.0 |
json
"JumpEvents": [
{
"EventId": "1",
"EventType": "Demand",
"DemandType": "AbsTransitory",
"TriggerTime": 1.25,
"TransitoryDurationMonths": 1,
"DemandPercent": 15
}
]
Notes
In the above example, the DemandPercent property value will increase absolute demand by 15% at 1.25 years for 1 month. Because this is transitory demand, Zypr will automatically add an additional Demand jump event, with a trigger time at 1.33 years (i.e., 1 month later), that reverses the initial transitory demand increase.
The ServiceDemandGrowthPercent property value in the EvolutionRules object is not modified, but service demand is assumed to continue during the transitory period. Therefore, the automatically generated demand value of the reversing Demand jump event will be higher than the initial demand increase.
The DemandPercent property value must be a positive number. The valid values for the TransitoryDurationMonths property are (1-6), inclusive.
This type of material shift in demand often arises in retail sales events, business functions with narrow windows of higher demand (e.g., healthcare insurance enrollment period), etc.
Increase pool utilization
This code block modifies the utilization boundaries in the EvolutionRules object. It increases the pool's average utilization boundaries from 60 to 65% to 65 to 70%.
May be used with Base Model A or Base Model B.
Key Objects
- EvolutionRules
- UtilizationBoundaries Jump Event
Repository Lookup Codes
Code | Version |
---|---|
U01 | 1.0 |
json
"JumpEvents": {
{
"EventId":"1",
"EventType":"UtilizationBoundaries",
"TriggerTime": 1.20,
"PoolUtilizationBoundaryPercentLower": 65.0,
"PoolUtilizationBoundaryPercentUpper": 70.0,
"RemoveServers": false
}
}
Notes
Shifting a pool's utilization boundaries upward can delay adding new servers to the pool to satisfy demand growth. This is a one-time event when the interval duration time increases as the upper utilization boundary is shifted from 65% to 70%.
Alternatively, it may be more desirable to remove this "extra" capacity (physically or logically) from the pool for use somewhere else. This is accomplished by setting the RemoveServers property to 'true'. How that is accomplished by Zypr depends on the type of simulation selected.
When the simulation type is 'Optimal', removing excess servers from the pool is based upon the preferred queue order (see InventoryQueueBias property). If the simulation type is 'Fixed', the queue order is oldest to newest and therefore will remove the oldest chronological age servers regardless if it meets the refresh age threshold set in ServerReplacementTime property in the SimulationRules object.
How higher hardware utilization is sustained
Sustaining higher hardware utilization rates usually requires improvement in two complementary domains:
- Automation of optimal workload assignment and scheduling to reduce perished (not utilized) resources of existing assets. A wide-variety of tools are available to address that challenge.
- Execute smaller capacity additions, at more frequent intervals, to optimally minimize the amount of existing assets subject to perishableness. This is an IT supply-chain challenge, which Zypr helps improve.
Add a constraint rule
This code block describes a constraint rule based upon server inventory balance.
This constraint may be added to either Base Model A or B. When applied to Base Model A, it should successfully complete with a solution. When applied to Bade Model B, with MetricTargetValue property still set to 226, Zypr will return no solution found response.
Key Objects
- Constraints
- HardwareBalance Constraint Object
Repository Lookup Codes
Code | Version |
---|---|
C01 | 1.0 |
json
"Constraints": [
{
"HardwareBalance": {
"Id": 1,
"MetricName": "Server",
"MetricConstraintOperator": "GreaterThan",
"MetricTargetValue": 226,
"TimeConstraintOperator": "AtOrAfter",
"TargetTime": 1.5,
}
}
]
Notes
A constraint is an expression of a desired limitation: what is not permitted. The above constraint therefore reads as follows:
"The server inventory balance is not permitted to be greater than 226 at or after the time of 1.5 years."
Constraints are particularly useful when other resources - software, space, power, network - are approaching a hard limitation and the cost to remove the resource limitation is significant. Constraints provide a means to 'bound' a forecast to respect the limitation, determine if a feasible solution even exists, and if so, at what cost. This can then be compared to the cost of a solution without the constraint plus the cost to remove the resource limitation itself.
Using Power Consumption Constraints
When applying constraints to power consumption, it is important that your model is "tuned" to reflect actual metered consumption rates, particularly if the objective is to remain below an absolute power consumption level. This is accomplished by adjusting properties in the PowerConsumptionTerms object.
Untuned PowerConsumptionTerms are often acceptable when used to compare relative differences in forecast scenarios, primarily because: 1) the same method is applied to all scenarios and the objective is too identify relative cost differences among scenarios, and 2) power consumption is often not a determining cost-factor for enterprise IT environments relative to hardware, software and space costs unless:
- data center space is rented from a colocation facility that uses power consumption as the primary price metric, or
- an owned data center is approaching maximum power load.
Software License Counting
Zypr refers to rules for determining required software licenses as Consumption Rules. Consumption Rules are classified as either "basic" or "conditional".
A basic rule has the same license metric as the physical unit used for counting, and requires no conditional logic.
If the required license quantity is 1:1 to the physical unit being counted, the ConsumptionRules object may be omitted. A 1:1 ratio is the default setting for a basic rule. Any other ratio requires you to specify the RequiredLicenseQty as illustrated below.
json
//example of 2:1 ratio
"ConsumptionRules": {
"Id": "1",
"RequiredLicenseQty": 2
}
//example of 0.5:1 ratio
"ConsumptionRules": {
"Id": "2",
"RequiredLicenseQty": .5
}
A conditional rule requires boolean logic to determined the required core license quantity.
The following examples for VMware®, RedHat® and Oracle® database illustrate how to define required license counting rules that involve conditional logic.
Create VMware® counting rule
This code block defines the ConsumptionRules object for a software license whose required license counting involves conditional logic.
This may be used for Base Model A or Base Model B.
Key Objects
- SoftwareInventoryTerms
- ConsumptionRules
Repository Lookup Codes
Code | Version |
---|---|
S01 | 1.0 |
json
"SoftwareInventoryTerms": [
{
"LicenseId": 1,
"LicenseMetric": "Processor",
"LicenseClass": "Perpetual",
"ContractType": "Coterminous",
"ContractTerms": {
"AnniversaryDate": "2024-10-31",
"TermLength": 3,
"CreateSettlementCalendar": "Union",
"RenewalSchedule": "Contract",
"AttemptPositionReset": false,
"CostRules": []
},
"Fee": 2000,
"PerpetualSupportPercent": 25,
"InitialPosition": null,
"ConsumptionRules": {
"Operator": "Or",
"Rules": [
{
"Id": "1",
"RequiredLicenseQty": 1,
"MetricName": "CoreSetSize",
"Operator": "LessThanOrEqual",
"TargetValue": 32
},
{
"Id": "2",
"RequiredLicenseQty": 2,
"MetricName": "CoreSetSize",
"Operator": "GreaterThan",
"TargetValue": 32
}
]
}
}
]
Notes
In the above code block, the ConsumptionRules object is highlighted. The counting rule is conditional because the LicenseMetric property value is 'Processor' but the counting method is based on different thresholds of 'Core' quantity.
The first level Operator property is set to 'Or', which indicates the rules contained in the Rule array are mutually exclusive. If the rules in the array prove not to be mutually exclusive when compared to actual physical inventory, it will cause the simulation to fail.
The MetricName property value specifies the physical inventory unit to evaluate. The consumption rules in the above code block reads as follows:
"When the physical quantity of cores per processor is less than or equal to 32, the required quantity of processor licenses is 1. When the physical quantity of cores per processor is greater than 32, the required quantity of processor licenses is 2."
The code block above illustrates rules for two different outcomes. The code block below extends the above example to demonstrate rules for three different outcomes.
json
"ConsumptionRules": {
"Operator": "Or",
"Rules": [
{
"Id": "1",
"RequiredLicenseQty": 1,
"MetricName": "CoreSetSize",
"Operator": "LessThanOrEqual",
"TargetValue": 32
},
{
"Id": 2,
"Operator": "And",
"RequiredLicenseQty": 2,
"Rules": [
{
"Id": "2.1",
"MetricName": "CoreSetSize",
"Operator": "GreaterThan",
"TargetValue": 32
},
{
"Id": "2.2",
"MetricName": "CoreSetSize",
"Operator": "LessThanOrEqual",
"TargetValue": 64
}
]
},
{
"Id": "3",
"RequiredLicenseQty": 3,
"MetricName": "CoreSetSize",
"Operator": "GreaterThan",
"TargetValue": 64
}
]
}
Create RedHat® counting rule
This code block defines the ConsumptionRules object for a software license whose required license counting involves conditional logic.
This may be used for Base Model A or Base Model B. Repository model includes use of Code property of ServerInventoryItem object.
Key Objects
- SoftwareInventoryTerms
- ConsumptionRules
- Code property of ServerInventoryItem
Repository Lookup Codes
Code | Version |
---|---|
S02 | 1.0 |
json
"SoftwareInventoryTerms": [
{
"LicenseId": 1,
"LicenseMetric": "Server",
"LicenseClass": "Subscription",
"ContractType": "Coterminous",
"ContractTerms": {
"AnniversaryDate": "2025-03-31",
"TermLength": 3,
"TrueUpMonth": 6,
"CreateSettlementCalendar": "Custom",
"RenewalSchedule" : "TrueUp",
"AttemptPositionReset": false,
"CostRules": []
},
"Fee": 4000,
"InitialPosition": null,
"ConsumptionRules": {
"Operator": "Or",
"Rules": [
{
"Id": "1",
"Operator": "Or",
"RequiredLicenseQty": 1,
"Rules": [
{
"Id": "1.1",
"MetricName": "ProcessorSetSize",
"Operator": "Equal",
"TargetValue": 1
},
{
"Id": "1.2",
"MetricName": "ProcessorSetSize",
"Operator": "Equal",
"TargetValue": 2
}
]
},
{
"Id": "2",
"RequiredLicenseQty": 2,
"MetricName": "ProcessorSetSize",
"Operator": "Equal",
"TargetValue": 4
},
{
"Id": "3",
"RequiredLicenseQty": 4,
"MetricName": "ProcessorSetSize",
"Operator": "Equal",
"TargetValue": 8
}
]
}
}
]
Notes
Rule Id 1 is constructed to illustrate rule nesting. When nesting boolean logic, the RequiredLicenseQty property is set to the same rule level in the hierarchy.
The more concise way to write Rule Ids 1.1 and 1.2 would be:
json
{
"Id": "1",
"RequiredLicenseQty": 1,
"MetricName": "ProcessorSetSize",
"Operator": "LessThanOrEqual",
"TargetValue": 2
}
The consumption rules in the full code block above reads as follows:
"When the physical processor set size of a server is 1 or 2, the required server license quantity is 1. When the physical processor set size of a server is 4, the required server license quantity is 2. When the physical processor set size of a server is 8, the required server license quantity is 4."
The ConsumptionRules object need only define counting rules for the type servers initially included in the ServerInventory object and any new type of servers that might be added to the pool, at later times, as defined by the then current state of the NewServerConfiguration object.
Create Oracle® Db counting rule
This code block defines the ConsumptionRules object for a software license that hose required fractional license .
This may be used for Base Model A or Base Model B.
Key Objects
- SoftwareInventoryTerms
- ConsumptionRules
Repository Lookup Codes
Code | Version |
---|---|
S03 | 1.0 |
json
"SoftwareInventoryTerms": [
{
"LicenseId": 1,
"LicenseMetric": "Core",
"LicenseClass": "Perpetual",
"ContractType": "Coterminous",
"ContractTerms": {
"AnniversaryDate": "2025-03-31",
"TermLength": 3,
"TrueUpMonth": 6,
"CreateSettlementCalendar": "Custom",
"RenewalSchedule" : "TrueUp",
"AttemptPositionReset": false,
"CostRules": []
},
"Fee": 15000,
"PerpetualSupportPercent": 30,
"InitialPosition": null,
"ConsumptionRules": {
"Id": "1",
"RequiredLicenseQty": 0.5
}
}
]
Notes
The consumption rules in the full code block above reads as follows:
"When the physical processor set size of a server is 1 or 2, the required server license quantity is 1. When the physical processor set size of a server is 4, the required server license quantity is 2. When the physical processor set size of a server is 8, the required server license quantity is 4."
The ConsumptionRules object need only define counting rules for the type servers initially included in the ServerInventory object and any new type of servers that might be added to the pool, at later times, as defined by the then current state of the NewServerConfiguration object.
Modify a software price
This code block modifies the fee of a software item.
This may be used with either Base Model A and B.
Key Objects
- SoftwareItem
- SoftwarePriceChange Jump Event
Repository Lookup Codes
Code | Version |
---|---|
S04 | 1.0 |
json
"JumpEvents":[
{
"EventId": "1",
"EventType": "SoftwarePriceChange",
"LicenseId": 3,
"TriggerTime": 1.5,
"Fee": 550
}
]
Notes
The code block above modifies the Fee property, of the SoftwareItem object with license #3, to 550 at the trigger time 1.5 years.
A Software Price Change may be used to modify a software item whose ContractType property is 'Instance' or 'Coterminous'. However, this jump event object may only be used for 'Coterminous' contract types only if all Schedule properties of all Rate objects in the CostRules are set to 'None'.
In other words, the Software Price Change jump event cannot be used to change a license fee or support percentage when the Cost Rules object is also attempting to change the same license fee or support percentage.
Create software price schedule
This code block defines price schedule using the Rate object.
This may be used with either Base Model A and B.
Key Objects
- SoftwareItem
- CostTerms
- CostRules
- Rate
Repository Lookup Codes
Code | Version |
---|---|
S05 | 1.0 |
json
"CostRules": [
{
"LicenseType" : "Perpetual",
"Rate": {
"Schedule": "TrueUp",
"ChangePercent": 5
}
},
{
"LicenseType" : "PerpetualSupport",
"Rate":{
"Schedule": "None",
"ChangePercent": 0
}
}
]
Notes
The example above sets a price schedule for the 'Perpetual' license Fee property of the SoftwareItem object that is increased 5% annually. Support is defined as a percentage of the perpetual license fee (see PerpetualSupportPercent property in SoftwareItem). In this example, the support cost will automatically increase by way of the perpetual license fee.
Alternatively, if a vendor is setting their price schedule for support by increasing the percentage rate, use the ChangePercent property for 'PerpetualSupport'.
For software items with the LicenseClass property of 'Perpetual', the LicenseType property of the CostRules must be either 'Perpetual', 'PerpetualSupport', or both. If the desired price schedule is for software items with the LicenseClass property of 'Subscription', the LicenseType property of the CostRules, if included, must equal 'Subscription'.
Set software fixed duration fee
This code block defines a fixed fee based on a fixed duration charge for incremental licenses within a selected settlement period.
This may be used with either Base Model A and B.
Key Objects
- SoftwareItem
- CostTerms
- CostRules
- Duration
Repository Lookup Codes
Code | Version |
---|---|
S06 | 1.0 |
json
"CostRules": [
{
"LicenseType" : "PerpetualSupport",
"Duration": {
"Schedule": "TrueUp",
"IntervalPercent": 50
}
}
]
Notes
The example above sets a fixed fee, based on a fixed duration, of 50% of the target schedule duration. In this example, the schedule is based on annual true-up. When an incremental license is added, the fixed fee will be based on 6 months, regardless of actual usage time.
A fixed duration rule may also be defined for a 'Subscription' license. It cannot be applied to a 'Perpetual' license, which does not have a Duration object.
Set when software cost is posted
This code block defines when a software cost is posted.
This may be used with either Base Model A and B.
Key Objects
- SoftwareItem
- CostTerms
- CostRules
Repository Lookup Codes
Code | Version |
---|---|
S07 | 1.0 |
json
"CostRules": [
{
"LicenseType" : "Perpetual",
"PostAt": "FirstUse"
},
{
"LicenseType" : "PerpetualSupport",
"PostAt": "TrueUp"
}
]
Notes
In the example above, when an incremental 'Perpetual' license fee is incurred, the cost for that license will be posted to the evolution time-interval when it is first required/used. In contrast, the associated costs for 'PerpetualSupport' is posted at the evolution time-interval that contains the next true-up date.
License settlement schedules enabling over-provisioning?
It is common practice for incremental increases in licenses to be settled at the next true-up or contract anniversary date. Delaying cost recognition tends to enable easy consumption.
The PostAt object provides the flexibility to better determine when such delays are, in fact, promoting unnecessary over-provisioning and higher cost for services.
Add software to stack
This code block adds a software item, at a future date, to a pool's software stack.
May be combined with Base Model A or Base Model B.
Key Objects
- SoftwareResources
- SoftwareStackAdd Jump Event
Repository Lookup Codes
Code | Version |
---|---|
S08 | 1.0 |
json
"SoftwareResources" : {
"PoolSoftwareStack": [1],
"SoftwareInventoryTerms": [
{
"LicenseId": 1,
"LicenseMetric": "Core",
"LicenseClass": "Subscription",
"ContractType": "Coterminous",
"ContractTerms": {
"AnniversaryDate" : "2024-03-31",
"TermLength": 3,
"AnnualTrueUpMonth": 9,
"CreateSettlementCalendar": "Union",
"RenewalSchedule": "Contract",
"CostRules": []
},
"Fee": 100,
"InitialPosition": null
},
{
"LicenseId": 2,
"LicenseMetric": "Core",
"LicenseClass": "Perpetual",
"ContractType": "Coterminous",
"ContractTerms": {
"AnniversaryDate" : "2025-06-01",
"TermLength": 3,
"AnnualTrueUpMonth": 9,
"CreateSettlementCalendar": "Union",
"RenewalSchedule": "Contract",
"CostRules": []
},
"Fee": 50,
"PerpetualSupportPercent": 25,
"InitialPosition": 0
}
]
}
"JumpEvents": [
{
"EventId": "1",
"EventType": "SoftwareStackAdd",
"TriggerTime": 0.5,
"LicenseIds": [2]
}
]
Notes
The SoftwareStackRegistry array defines the composition of a pool's initial software stack at time zero. In the code block above, the software stack only includes license #1. Only software items in the software stack may incur a cost.
To add one or more software items to a pool's software stack at a future time, the software items need to be defined in the SoftwareInventoryTerms array. The SoftwareStackAdd jump event object must reference software items not already in the software stack.
In the above code block, license #2 is added to the SoftwareStackRegistry at trigger time .5 years.
To designate the initial license position of license #2 at trigger time .5 years, use the InitialPosition property to set a value. In the above code block, license #2 has an initial license position of 0. If the InitialPosition property was set to null, Zypr will set the initial license position to the actual hardware unit balance at the trigger time of .5 years.
TIP
Only software items with a meaningful monetary cost need be included in the pool's software stack. The SoftwareInventoryTerms array object is not intended to replicate a CMDB or a SAM tool. Those tools often serve as data sources.
Remove software from stack
This code block removes a software item, at a future date, from a pool's software stack.
This may be used for Base Model A or Base Model B.
Key Objects
- SoftwareResources
- SoftwareStackAdd Jump Event
Repository Lookup Codes
Code | Version |
---|---|
S09 | 1.0 |
json
"SoftwareResources" : {
"PoolSoftwareStack": [1,2],
"SoftwareInventoryTerms": [
{
"LicenseId": 1,
"LicenseMetric": "Core",
"LicenseClass": "Subscription",
"ContractType": "Coterminous",
"ContractTerms": {
"AnniversaryDate" : "2024-03-31",
"TermLength": 3,
"AnnualTrueUpMonth": 9,
"CreateSettlementCalendar": "Union",
"RenewalSchedule": "Contract",
"CostRules": []
},
"Fee": 100,
"InitialPosition": null
},
{
"LicenseId": 2,
"LicenseMetric": "Core",
"LicenseClass": "Perpetual",
"ContractType": "Coterminous",
"ContractTerms": {
"AnniversaryDate" : "2025-06-01",
"TermLength": 3,
"AnnualTrueUpMonth": 9,
"CreateSettlementCalendar": "Union",
"RenewalSchedule": "Contract",
"CostRules": []
},
"Fee": 50,
"PerpetualSupportPercent": 25,
"InitialPosition": 0
}
]
}
"JumpEvents": [
{
"EventId": "1",
"EventType": "SoftwareStackRemove",
"TriggerTime": 0.5,
"LicenseIds": [2]
}
]
Notes
To remove a software item from a pool's software stack at a future time, the software item must already be included in the SoftwareStackRegistry. Use the SoftwareStackRemove jump event object to define when the software item should be removed from the SoftwareStackRegistry. After a software item is removed from the software stack, no further costs associated with the license are incurred by the pool.
In the code block above, license id #2 is being remove from the pool's stack at trigger time 0.5 years.
Reduce license position
The SoftwareSummary object identifies software licenses that are projected to be underutilized. However, it doesn't necessarily answer how under-utilization may be remedied and how costs might be reduced.
The AttemptPositionReset property is a feature to identify how that might be feasibly accomplished. The feature implies "consumption-based" contract terms that permit, or need to permit in the future, reduction to existing license usage, and corresponding costs, or reassignment of entitlements towards other applications(offered by the vendor).
The code block below will attempt to reset license positions to a lower level over the duration of the simulation. This feature only applies to 'Coterminous' contract types.
This may be used for Base Model A or Base Model B.
Key Objects
- SoftwareInventoryTerms object.
- SoftwareItem object.
- ContractTerms object.
Repository Lookup Codes
Code | Version |
---|---|
S10 | 1.0 |
json
"SoftwareInventoryTerms": [
{
"LicenseId": 1,
"LicenseMetric": "Processor",
"LicenseClass": "Subscription",
"ContractType": "Coterminous",
"ContractTerms": {
"AnniversaryDate" : "2024-10-1",
"TermLength": 3,
"AnnualTrueUpMonth": 9,
"CreateSettlementCalendar": "Union",
"RenewalSchedule": "Contract",
"AttemptPositionReset": true
},
"Fee": 2000,
"InitialPosition": null
}
]
Notes
Actual consumption for 'Coterminous' contract types is based on maximum (peak) quantity consumed, which carries forward to the next true-up or contract term. Zypr will attempt to reduce license positions, at contractually permissible windows, in a manner that doesn't later cause positions to "re-acquire" a higher license position resulting in higher costs. Therefore, Zypr cannot guarantee a reset to a lower position is feasible.
For the example above, the RenewalSchedule property is set to 'Contract'. Only at each contract anniversary date (i.e., 3-year intervals), Zypr will attempt to reduce license positions. Alternatively, by setting the RenewalSchedule property to 'TrueUp', Zypr will attempt to reduce license positions annually corresponding to the true-up date.