Example: Charging a leaf allocation with missing credits (Absolute)¶
Frequency of use | Common |
---|---|
Actors |
|
Communication Flow: Kotlin
/* In this example, we will show what happens when an allocation is unable to carry the full charge.
We will be using a more complex hierarchy. The hierarchy will have a single root. The root has a
single child, the 'node' allocation. This node has a single child allocation, the leaf. The leaf
has no children. */
Wallets.browse.call(
WalletBrowseRequest(
consistency = null,
filterType = null,
itemsPerPage = null,
itemsToSkip = null,
next = null,
),
piRoot
).orThrow()
/*
PageV2(
items = listOf(Wallet(
allocations = listOf(WalletAllocation(
allocationPath = listOf("42"),
allowSubAllocationsToAllocate = true,
balance = 550,
canAllocate = false,
endDate = null,
grantedIn = 1,
id = "42",
initialBalance = 1000,
localBalance = 1000,
startDate = 1633941615074,
)),
chargePolicy = AllocationSelectorPolicy.EXPIRE_FIRST,
chargeType = ChargeType.ABSOLUTE,
owner = WalletOwner.Project(
projectId = "root-project",
),
paysFor = ProductCategoryId(
id = "example-slim",
name = "example-slim",
provider = "example",
),
productType = ProductType.COMPUTE,
unit = ProductPriceUnit.UNITS_PER_HOUR,
)),
itemsPerPage = 50,
next = null,
)
*/
Wallets.browse.call(
WalletBrowseRequest(
consistency = null,
filterType = null,
itemsPerPage = null,
itemsToSkip = null,
next = null,
),
piNode
).orThrow()
/*
PageV2(
items = listOf(Wallet(
allocations = listOf(WalletAllocation(
allocationPath = listOf("42", "52"),
allowSubAllocationsToAllocate = true,
balance = 50,
canAllocate = false,
endDate = null,
grantedIn = 1,
id = "52",
initialBalance = 500,
localBalance = 100,
startDate = 1633941615074,
)),
chargePolicy = AllocationSelectorPolicy.EXPIRE_FIRST,
chargeType = ChargeType.ABSOLUTE,
owner = WalletOwner.Project(
projectId = "node-project",
),
paysFor = ProductCategoryId(
id = "example-slim",
name = "example-slim",
provider = "example",
),
productType = ProductType.COMPUTE,
unit = ProductPriceUnit.UNITS_PER_HOUR,
)),
itemsPerPage = 50,
next = null,
)
*/
Wallets.browse.call(
WalletBrowseRequest(
consistency = null,
filterType = null,
itemsPerPage = null,
itemsToSkip = null,
next = null,
),
piLeaf
).orThrow()
/*
PageV2(
items = listOf(Wallet(
allocations = listOf(WalletAllocation(
allocationPath = listOf("42", "52", "62"),
allowSubAllocationsToAllocate = true,
balance = 450,
canAllocate = false,
endDate = null,
grantedIn = 1,
id = "62",
initialBalance = 500,
localBalance = 450,
startDate = 1633941615074,
)),
chargePolicy = AllocationSelectorPolicy.EXPIRE_FIRST,
chargeType = ChargeType.ABSOLUTE,
owner = WalletOwner.Project(
projectId = "leaf-project",
),
paysFor = ProductCategoryId(
id = "example-slim",
name = "example-slim",
provider = "example",
),
productType = ProductType.COMPUTE,
unit = ProductPriceUnit.UNITS_PER_HOUR,
)),
itemsPerPage = 50,
next = null,
)
*/
/* As we can see from the allocations, they have already been in use. To be concrete, you can reach
this state by applying a 400 core hour charge on the node and another 50 core hours on the leaf. */
/* We now attempt to perform a charge of 100 core hours on the leaf. */
Accounting.charge.call(
bulkRequestOf(ChargeWalletRequestItem(
description = "A charge for compute usage",
payer = WalletOwner.Project(
projectId = "leaf-project",
),
performedBy = "user",
periods = 1,
product = ProductReference(
category = "example-slim",
id = "example-slim-1",
provider = "example",
),
transactionId = "charge-1",
units = 100,
)),
ucloud
).orThrow()
/*
BulkResponse(
responses = listOf(false),
)
*/
/* Even though the leaf, seen in isolation, has enough credits. The failure occurs in the node which,
before the charge, only has 50 core hours remaining. */
Wallets.browse.call(
WalletBrowseRequest(
consistency = null,
filterType = null,
itemsPerPage = null,
itemsToSkip = null,
next = null,
),
piRoot
).orThrow()
/*
PageV2(
items = listOf(Wallet(
allocations = listOf(WalletAllocation(
allocationPath = listOf("42"),
allowSubAllocationsToAllocate = true,
balance = 450,
canAllocate = false,
endDate = null,
grantedIn = 1,
id = "42",
initialBalance = 1000,
localBalance = 1000,
startDate = 1633941615074,
)),
chargePolicy = AllocationSelectorPolicy.EXPIRE_FIRST,
chargeType = ChargeType.ABSOLUTE,
owner = WalletOwner.Project(
projectId = "root-project",
),
paysFor = ProductCategoryId(
id = "example-slim",
name = "example-slim",
provider = "example",
),
productType = ProductType.COMPUTE,
unit = ProductPriceUnit.UNITS_PER_HOUR,
)),
itemsPerPage = 50,
next = null,
)
*/
Wallets.browse.call(
WalletBrowseRequest(
consistency = null,
filterType = null,
itemsPerPage = null,
itemsToSkip = null,
next = null,
),
piNode
).orThrow()
/*
PageV2(
items = listOf(Wallet(
allocations = listOf(WalletAllocation(
allocationPath = listOf("42", "52"),
allowSubAllocationsToAllocate = true,
balance = -50,
canAllocate = false,
endDate = null,
grantedIn = 1,
id = "52",
initialBalance = 500,
localBalance = 100,
startDate = 1633941615074,
)),
chargePolicy = AllocationSelectorPolicy.EXPIRE_FIRST,
chargeType = ChargeType.ABSOLUTE,
owner = WalletOwner.Project(
projectId = "node-project",
),
paysFor = ProductCategoryId(
id = "example-slim",
name = "example-slim",
provider = "example",
),
productType = ProductType.COMPUTE,
unit = ProductPriceUnit.UNITS_PER_HOUR,
)),
itemsPerPage = 50,
next = null,
)
*/
Wallets.browse.call(
WalletBrowseRequest(
consistency = null,
filterType = null,
itemsPerPage = null,
itemsToSkip = null,
next = null,
),
piLeaf
).orThrow()
/*
PageV2(
items = listOf(Wallet(
allocations = listOf(WalletAllocation(
allocationPath = listOf("42", "52", "62"),
allowSubAllocationsToAllocate = true,
balance = 350,
canAllocate = false,
endDate = null,
grantedIn = 1,
id = "62",
initialBalance = 500,
localBalance = 350,
startDate = 1633941615074,
)),
chargePolicy = AllocationSelectorPolicy.EXPIRE_FIRST,
chargeType = ChargeType.ABSOLUTE,
owner = WalletOwner.Project(
projectId = "leaf-project",
),
paysFor = ProductCategoryId(
id = "example-slim",
name = "example-slim",
provider = "example",
),
productType = ProductType.COMPUTE,
unit = ProductPriceUnit.UNITS_PER_HOUR,
)),
itemsPerPage = 50,
next = null,
)
*/
/* When we apply the charge, the node reaches a negative balance. If any allocation reaches a negative
balance, then the charge has failed. As we can see, it is possible for a balance to go into the
negatives. */
Communication Flow: Curl
# ------------------------------------------------------------------------------------------------------
# $host is the UCloud instance to contact. Example: 'http://localhost:8080' or 'https://cloud.sdu.dk'
# $accessToken is a valid access-token issued by UCloud
# ------------------------------------------------------------------------------------------------------
# In this example, we will show what happens when an allocation is unable to carry the full charge.
# We will be using a more complex hierarchy. The hierarchy will have a single root. The root has a
# single child, the 'node' allocation. This node has a single child allocation, the leaf. The leaf
# has no children.
# Authenticated as piRoot
curl -XGET -H "Authorization: Bearer $accessToken" "$host/api/accounting/wallets/browse?"
# {
# "itemsPerPage": 50,
# "items": [
# {
# "owner": {
# "type": "project",
# "projectId": "root-project"
# },
# "paysFor": {
# "name": "example-slim",
# "provider": "example"
# },
# "allocations": [
# {
# "id": "42",
# "allocationPath": [
# "42"
# ],
# "balance": 550,
# "initialBalance": 1000,
# "localBalance": 1000,
# "startDate": 1633941615074,
# "endDate": null,
# "grantedIn": 1,
# "canAllocate": false,
# "allowSubAllocationsToAllocate": true
# }
# ],
# "chargePolicy": "EXPIRE_FIRST",
# "productType": "COMPUTE",
# "chargeType": "ABSOLUTE",
# "unit": "UNITS_PER_HOUR"
# }
# ],
# "next": null
# }
# Authenticated as piNode
curl -XGET -H "Authorization: Bearer $accessToken" "$host/api/accounting/wallets/browse?"
# {
# "itemsPerPage": 50,
# "items": [
# {
# "owner": {
# "type": "project",
# "projectId": "node-project"
# },
# "paysFor": {
# "name": "example-slim",
# "provider": "example"
# },
# "allocations": [
# {
# "id": "52",
# "allocationPath": [
# "42",
# "52"
# ],
# "balance": 50,
# "initialBalance": 500,
# "localBalance": 100,
# "startDate": 1633941615074,
# "endDate": null,
# "grantedIn": 1,
# "canAllocate": false,
# "allowSubAllocationsToAllocate": true
# }
# ],
# "chargePolicy": "EXPIRE_FIRST",
# "productType": "COMPUTE",
# "chargeType": "ABSOLUTE",
# "unit": "UNITS_PER_HOUR"
# }
# ],
# "next": null
# }
# Authenticated as piLeaf
curl -XGET -H "Authorization: Bearer $accessToken" "$host/api/accounting/wallets/browse?"
# {
# "itemsPerPage": 50,
# "items": [
# {
# "owner": {
# "type": "project",
# "projectId": "leaf-project"
# },
# "paysFor": {
# "name": "example-slim",
# "provider": "example"
# },
# "allocations": [
# {
# "id": "62",
# "allocationPath": [
# "42",
# "52",
# "62"
# ],
# "balance": 450,
# "initialBalance": 500,
# "localBalance": 450,
# "startDate": 1633941615074,
# "endDate": null,
# "grantedIn": 1,
# "canAllocate": false,
# "allowSubAllocationsToAllocate": true
# }
# ],
# "chargePolicy": "EXPIRE_FIRST",
# "productType": "COMPUTE",
# "chargeType": "ABSOLUTE",
# "unit": "UNITS_PER_HOUR"
# }
# ],
# "next": null
# }
# As we can see from the allocations, they have already been in use. To be concrete, you can reach
# this state by applying a 400 core hour charge on the node and another 50 core hours on the leaf.
# We now attempt to perform a charge of 100 core hours on the leaf.
# Authenticated as ucloud
curl -XPOST -H "Authorization: Bearer $accessToken" -H "Content-Type: content-type: application/json; charset=utf-8" "$host/api/accounting/charge" -d '{
"items": [
{
"payer": {
"type": "project",
"projectId": "leaf-project"
},
"units": 100,
"periods": 1,
"product": {
"id": "example-slim-1",
"category": "example-slim",
"provider": "example"
},
"performedBy": "user",
"description": "A charge for compute usage",
"transactionId": "charge-1"
}
]
}'
# {
# "responses": [
# false
# ]
# }
# Even though the leaf, seen in isolation, has enough credits. The failure occurs in the node which,
# before the charge, only has 50 core hours remaining.
# Authenticated as piRoot
curl -XGET -H "Authorization: Bearer $accessToken" "$host/api/accounting/wallets/browse?"
# {
# "itemsPerPage": 50,
# "items": [
# {
# "owner": {
# "type": "project",
# "projectId": "root-project"
# },
# "paysFor": {
# "name": "example-slim",
# "provider": "example"
# },
# "allocations": [
# {
# "id": "42",
# "allocationPath": [
# "42"
# ],
# "balance": 450,
# "initialBalance": 1000,
# "localBalance": 1000,
# "startDate": 1633941615074,
# "endDate": null,
# "grantedIn": 1,
# "canAllocate": false,
# "allowSubAllocationsToAllocate": true
# }
# ],
# "chargePolicy": "EXPIRE_FIRST",
# "productType": "COMPUTE",
# "chargeType": "ABSOLUTE",
# "unit": "UNITS_PER_HOUR"
# }
# ],
# "next": null
# }
# Authenticated as piNode
curl -XGET -H "Authorization: Bearer $accessToken" "$host/api/accounting/wallets/browse?"
# {
# "itemsPerPage": 50,
# "items": [
# {
# "owner": {
# "type": "project",
# "projectId": "node-project"
# },
# "paysFor": {
# "name": "example-slim",
# "provider": "example"
# },
# "allocations": [
# {
# "id": "52",
# "allocationPath": [
# "42",
# "52"
# ],
# "balance": -50,
# "initialBalance": 500,
# "localBalance": 100,
# "startDate": 1633941615074,
# "endDate": null,
# "grantedIn": 1,
# "canAllocate": false,
# "allowSubAllocationsToAllocate": true
# }
# ],
# "chargePolicy": "EXPIRE_FIRST",
# "productType": "COMPUTE",
# "chargeType": "ABSOLUTE",
# "unit": "UNITS_PER_HOUR"
# }
# ],
# "next": null
# }
# Authenticated as piLeaf
curl -XGET -H "Authorization: Bearer $accessToken" "$host/api/accounting/wallets/browse?"
# {
# "itemsPerPage": 50,
# "items": [
# {
# "owner": {
# "type": "project",
# "projectId": "leaf-project"
# },
# "paysFor": {
# "name": "example-slim",
# "provider": "example"
# },
# "allocations": [
# {
# "id": "62",
# "allocationPath": [
# "42",
# "52",
# "62"
# ],
# "balance": 350,
# "initialBalance": 500,
# "localBalance": 350,
# "startDate": 1633941615074,
# "endDate": null,
# "grantedIn": 1,
# "canAllocate": false,
# "allowSubAllocationsToAllocate": true
# }
# ],
# "chargePolicy": "EXPIRE_FIRST",
# "productType": "COMPUTE",
# "chargeType": "ABSOLUTE",
# "unit": "UNITS_PER_HOUR"
# }
# ],
# "next": null
# }
# When we apply the charge, the node reaches a negative balance. If any allocation reaches a negative
# balance, then the charge has failed. As we can see, it is possible for a balance to go into the
# negatives.