Resources are the base abstraction used for orchestration in UCloud.
Rationale
In this article, we will take a closer look at what we mean when we say that UCloud is an orchestrator of resources. Before you begin, we recommend that you have already read about:
Providers: Exposes compute and storage resources to end-users.
Products: Defines the services exposed by providers.
Wallets: Holds allocations which grant access to products.
UCloud uses the resource abstraction to synchronize tasks between UCloud/Core and providers. As a result, resources are often used to describe work for the provider. For example, a computational Job is one type of resource used in UCloud.
To understand how resources work, we will first examine what all resources have in common:
A set of unique identifiers: Users and services can reference resources by using a unique ID.
Product and provider reference: Most resources describe a work of a provider. As a result, these resources must have a backing product.
A resource specification: Describes the resource. For example, this could be the parameters of a computational Job
Ownership and permissions: All resources have exactly one workspace owner.
Updates and status: Providers can send regular updates about a resource. These update describe changes in the system. These changes in turn affect the current status.
The Catalog
UCloud, in almost all cases, store a record of all resources in use. We refer to this datastore as the catalog of UCloud. As a result, UCloud/Core can fulfil some operations without involving the provider. In particular, UCloud/Core performs many read operations without the provider's involvement.
End-users interact with all resources through a standardized API. The API provides common CRUD operations along with permission related operations. Concrete resources further extend this API with resource specific tasks. For example, virtual machines expose an operation to shut down the machine.
On this page we will discuss the end-user API. But on the following pages, you can discover the siblings of this API used by providers:
UCloud/Core invokes the Provider API to proxy information from the end-user API
The provider invokes the Control API to register changes in UCloud/Core
The Permission Model
UCloud uses a RBAC based permission model. As a workspace administrator, you must assign permissions for resources to workspace groups.
Currently, UCloud has the following permissions:
READ: Grants access to operations which return a resource
EDIT: Grants access to operations which modify a resource
ADMIN: Grants access to privileged operations which read or modify a resource. Workspace administrators hold this permission. It is not possible to grant this permission through example.updateAcl.
PROVIDER: Grants access to privileged operations which read or modify a resource. Implicit permission granted to providers of a resource. It is not possible to grant this permission through example.updateAcl.
UCloud/Core checks all permissions before proxying information to the provider. However, this doesn't mean that an operation must succeed once it reaches a provider. Providers can perform additional permission checking once a request arrives.
Feature Detection
The resource API has support for feature detection. This happens through the example.retrieveProducts operation. Feature detection is specific to concrete resources. In general terms, feature detection can change:
A provider might only support a subset of fields (of a data model).
Some operations might be optional. A provider can declare support for advanced features.
A provider might only support a subset of operation workloads. They can require work to follow a certain structure. For example, a provider might declare support for containers but not for virtual machines.
A Note on the Examples
In the examples, we will work with a simple resource, used only in examples. This resource instructs the provider to count from one integer to another integer. The end-user specifies these numbers in the specification. The provider communicates the progress through updates. End-users can read the current progress from the status property.
By default, all providers support counting "forward" (in the positive direction). However, providers must declare that they support counting "backwards" (negative direction). If they do not declare support for this, then UCloud/Core will reject all requests counting backwards.
/* In this example, we will discover how a user can browse their catalog. This is done through thebrowse operation. The browse operation exposes the results using the pagination API of UCloud.As we will see later, it is possible to filter in the results returned using the flags of theoperation. */Resources.browse.call(ResourceBrowseRequest( consistency =null, flags =ExampleResourceFlags( filterCreatedAfter =null, filterCreatedBefore =null, filterCreatedBy =null, filterIds =null, filterProductCategory =null, filterProductId =null, filterProvider =null, filterProviderIds =null, filterState =null, hideProductCategory =null, hideProductId =null, hideProvider =null, includeOthers =false, includeProduct =false, includeSupport =false, includeUpdates =false, ), itemsPerPage =null, itemsToSkip =null, next =null, sortBy =null, sortDirection =null, ), user).orThrow()/*PageV2( items = listOf(ExampleResource( createdAt = 1635170395571, id = "1234", owner = ResourceOwner( createdBy = "user", project = null, ), permissions = ResourcePermissions( myself = listOf(Permission.ADMIN), others = emptyList(), ), specification = ExampleResource.Spec( product = ProductReference( category = "example-compute", id = "example-compute", provider = "example", ), start = 0, target = 100, ), status = ExampleResource.Status( resolvedProduct = null, resolvedSupport = null, state = State.RUNNING, value = 10, ), updates = listOf(ExampleResource.Update( currentValue = null, newState = State.PENDING, status = "We are about to start counting!", timestamp = 1635170395571, ), ExampleResource.Update( currentValue = 10, newState = State.RUNNING, status = "We are now counting!", timestamp = 1635170395571, )), providerGeneratedId = "1234", )), itemsPerPage = 50, next = null, )*//* 📝 NOTE: The provider has already started counting. You can observe the changes which lead to thecurrent status through the updates. */
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 discover how a user can browse their catalog. This is done through the# browse operation. The browse operation exposes the results using the pagination API of UCloud.# # As we will see later, it is possible to filter in the results returned using the flags of the# operation.# Authenticated as usercurl -XGET -H "Authorization: Bearer $accessToken" "$host/api/example/browse?includeOthers=false&includeUpdates=false&includeSupport=false&includeProduct=false"
# {# "itemsPerPage": 50,# "items": [# {# "id": "1234",# "specification": {# "start": 0,# "target": 100,# "product": {# "id": "example-compute",# "category": "example-compute",# "provider": "example"# }# },# "createdAt": 1635170395571,# "status": {# "state": "RUNNING",# "value": 10,# "resolvedSupport": null,# "resolvedProduct": null# },# "updates": [# {# "timestamp": 1635170395571,# "status": "We are about to start counting!",# "newState": "PENDING",# "currentValue": null# },# {# "timestamp": 1635170395571,# "status": "We are now counting!",# "newState": "RUNNING",# "currentValue": 10# }# ],# "owner": {# "createdBy": "user",# "project": null# },# "permissions": {# "myself": [# "ADMIN"# ],# "others": [# ]# }# }# ],# "next": null# }# 📝 NOTE: The provider has already started counting. You can observe the changes which lead to the# current status through the updates.
Communication Flow: Visual
Example: Creating and retrieving a resource
Frequency of use
Common
Actors
An authenticated user (user)
Communication Flow: Kotlin
/* In this example, we will discover how to create a resource and retrieve information about it. */Resources.create.call(bulkRequestOf(ExampleResource.Spec( product =ProductReference( category ="example-compute", id ="example-compute", provider ="example", ), start =0, target =100, )), user).orThrow()/*BulkResponse( responses = listOf(FindByStringId( id = "1234", )), )*//* 📝 NOTE: Users only specify the specification when they wish to create a resource. The specificationdefines the values which are in the control of the user. The specification remains immutablefor the resource's lifetime. Mutable values are instead listed in the status. */Resources.retrieve.call(ResourceRetrieveRequest( flags =ExampleResourceFlags( filterCreatedAfter =null, filterCreatedBefore =null, filterCreatedBy =null, filterIds =null, filterProductCategory =null, filterProductId =null, filterProvider =null, filterProviderIds =null, filterState =null, hideProductCategory =null, hideProductId =null, hideProvider =null, includeOthers =false, includeProduct =false, includeSupport =false, includeUpdates =false, ), id ="1234", ), user).orThrow()/*ExampleResource( createdAt = 1635170395571, id = "1234", owner = ResourceOwner( createdBy = "user", project = null, ), permissions = ResourcePermissions( myself = listOf(Permission.ADMIN), others = emptyList(), ), specification = ExampleResource.Spec( product = ProductReference( category = "example-compute", id = "example-compute", provider = "example", ), start = 0, target = 100, ), status = ExampleResource.Status( resolvedProduct = null, resolvedSupport = null, state = State.RUNNING, value = 10, ), updates = listOf(ExampleResource.Update( currentValue = null, newState = State.PENDING, status = "We are about to start counting!", timestamp = 1635170395571, ), ExampleResource.Update( currentValue = 10, newState = State.RUNNING, status = "We are now counting!", timestamp = 1635170395571, )), providerGeneratedId = "1234", )*/
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 discover how to create a resource and retrieve information about it.# Authenticated as usercurl -XPOST -H "Authorization: Bearer $accessToken" -H "Content-Type: content-type: application/json; charset=utf-8" "$host/api/example" -d '{
"items": [ {"start":0,"target":100,"product":{"id":"example-compute","category":"example-compute","provider":"example" } } ]}'# {# "responses": [# {# "id": "1234"# }# ]# }# 📝 NOTE: Users only specify the specification when they wish to create a resource. The specification# defines the values which are in the control of the user. The specification remains immutable# for the resource's lifetime. Mutable values are instead listed in the status.curl -XGET -H "Authorization: Bearer $accessToken" "$host/api/example/retrieve?includeOthers=false&includeUpdates=false&includeSupport=false&includeProduct=false&id=1234"
# {# "id": "1234",# "specification": {# "start": 0,# "target": 100,# "product": {# "id": "example-compute",# "category": "example-compute",# "provider": "example"# }# },# "createdAt": 1635170395571,# "status": {# "state": "RUNNING",# "value": 10,# "resolvedSupport": null,# "resolvedProduct": null# },# "updates": [# {# "timestamp": 1635170395571,# "status": "We are about to start counting!",# "newState": "PENDING",# "currentValue": null# },# {# "timestamp": 1635170395571,# "status": "We are now counting!",# "newState": "RUNNING",# "currentValue": 10# }# ],# "owner": {# "createdBy": "user",# "project": null# },# "permissions": {# "myself": [# "ADMIN"# ],# "others": [# ]# }# }
Communication Flow: Visual
Example: Browsing the catalog with a filter
Frequency of use
Common
Actors
An authenticated user (user)
Communication Flow: Kotlin
/* In this example, we will look at the flags which are passed to both browse and retrieve operations.This value is used to:- Filter out values: These properties are prefixed by filter* and remove results from the response. When used in a retrieve operation, this will cause a 404 if no results are found.- Include additional data: These properties are prefixed by include* and can be used to load additional data. This data is returned as part of the status object. The intention of these are to save the client a round-trip by retrieving all relevant data in a single call. */Resources.browse.call(ResourceBrowseRequest( consistency =null, flags =ExampleResourceFlags( filterCreatedAfter =null, filterCreatedBefore =null, filterCreatedBy =null, filterIds =null, filterProductCategory =null, filterProductId =null, filterProvider =null, filterProviderIds =null, filterState = State.RUNNING, hideProductCategory =null, hideProductId =null, hideProvider =null, includeOthers =false, includeProduct =false, includeSupport =false, includeUpdates =false, ), itemsPerPage =null, itemsToSkip =null, next =null, sortBy =null, sortDirection =null, ), user).orThrow()/*PageV2( items = listOf(ExampleResource( createdAt = 1635170395571, id = "1234", owner = ResourceOwner( createdBy = "user", project = null, ), permissions = ResourcePermissions( myself = listOf(Permission.ADMIN), others = emptyList(), ), specification = ExampleResource.Spec( product = ProductReference( category = "example-compute", id = "example-compute", provider = "example", ), start = 0, target = 100, ), status = ExampleResource.Status( resolvedProduct = null, resolvedSupport = null, state = State.RUNNING, value = 10, ), updates = listOf(ExampleResource.Update( currentValue = null, newState = State.PENDING, status = "We are about to start counting!", timestamp = 1635170395571, ), ExampleResource.Update( currentValue = 10, newState = State.RUNNING, status = "We are now counting!", timestamp = 1635170395571, )), providerGeneratedId = "1234", )), itemsPerPage = 50, next = null, )*/
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 look at the flags which are passed to both browse and retrieve operations.# This value is used to:# # - Filter out values: These properties are prefixed by filter* and remove results from the response.# When used in a retrieve operation, this will cause a 404 if no results are found.# - Include additional data: These properties are prefixed by include* and can be used to load # additional data. This data is returned as part of the status object. The intention of these are to# save the client a round-trip by retrieving all relevant data in a single call.# Authenticated as usercurl -XGET -H "Authorization: Bearer $accessToken" "$host/api/example/browse?filterState=RUNNING&includeOthers=false&includeUpdates=false&includeSupport=false&includeProduct=false"
# {# "itemsPerPage": 50,# "items": [# {# "id": "1234",# "specification": {# "start": 0,# "target": 100,# "product": {# "id": "example-compute",# "category": "example-compute",# "provider": "example"# }# },# "createdAt": 1635170395571,# "status": {# "state": "RUNNING",# "value": 10,# "resolvedSupport": null,# "resolvedProduct": null# },# "updates": [# {# "timestamp": 1635170395571,# "status": "We are about to start counting!",# "newState": "PENDING",# "currentValue": null# },# {# "timestamp": 1635170395571,# "status": "We are now counting!",# "newState": "RUNNING",# "currentValue": 10# }# ],# "owner": {# "createdBy": "user",# "project": null# },# "permissions": {# "myself": [# "ADMIN"# ],# "others": [# ]# }# }# ],# "next": null# }
Communication Flow: Visual
Example: Searching for data
Frequency of use
Common
Actors
An authenticated user (user)
Communication Flow: Kotlin
/* In this example, we will discover the search functionality of resources. Search allows for free-textqueries which attempts to find relevant results. This is very different from browse with filters, since 'relevancy' is a vaguely defined concept. Search is not guaranteed to return results in anydeterministic fashion, unlike browse. *//* We start with the following dataset. */Resources.browse.call(ResourceBrowseRequest( consistency =null, flags =ExampleResourceFlags( filterCreatedAfter =null, filterCreatedBefore =null, filterCreatedBy =null, filterIds =null, filterProductCategory =null, filterProductId =null, filterProvider =null, filterProviderIds =null, filterState = State.RUNNING, hideProductCategory =null, hideProductId =null, hideProvider =null, includeOthers =false, includeProduct =false, includeSupport =false, includeUpdates =false, ), itemsPerPage =null, itemsToSkip =null, next =null, sortBy =null, sortDirection =null, ), user).orThrow()/*PageV2( items = listOf(ExampleResource( createdAt = 1635170395571, id = "1", owner = ResourceOwner( createdBy = "user", project = null, ), permissions = ResourcePermissions( myself = listOf(Permission.ADMIN), others = emptyList(), ), specification = ExampleResource.Spec( product = ProductReference( category = "example-compute", id = "example-compute", provider = "example", ), start = 0, target = 100, ), status = ExampleResource.Status( resolvedProduct = null, resolvedSupport = null, state = State.RUNNING, value = 10, ), updates = emptyList(), providerGeneratedId = "1", ), ExampleResource( createdAt = 1635170395571, id = "2", owner = ResourceOwner( createdBy = "user", project = null, ), permissions = ResourcePermissions( myself = listOf(Permission.ADMIN), others = emptyList(), ), specification = ExampleResource.Spec( product = ProductReference( category = "example-compute", id = "example-compute", provider = "example", ), start = 0, target = 200, ), status = ExampleResource.Status( resolvedProduct = null, resolvedSupport = null, state = State.RUNNING, value = 10, ), updates = emptyList(), providerGeneratedId = "2", ), ExampleResource( createdAt = 1635170395571, id = "3", owner = ResourceOwner( createdBy = "user", project = null, ), permissions = ResourcePermissions( myself = listOf(Permission.ADMIN), others = emptyList(), ), specification = ExampleResource.Spec( product = ProductReference( category = "example-compute", id = "example-compute", provider = "example", ), start = 0, target = 300, ), status = ExampleResource.Status( resolvedProduct = null, resolvedSupport = null, state = State.RUNNING, value = 10, ), updates = emptyList(), providerGeneratedId = "3", )), itemsPerPage = 50, next = null, )*//* Search may look in many different fields to determine if a result is relevant. Searching for thevalue 300 might produce the following results. */Resources.search.call(ResourceSearchRequest( consistency =null, flags =ExampleResourceFlags( filterCreatedAfter =null, filterCreatedBefore =null, filterCreatedBy =null, filterIds =null, filterProductCategory =null, filterProductId =null, filterProvider =null, filterProviderIds =null, filterState =null, hideProductCategory =null, hideProductId =null, hideProvider =null, includeOthers =false, includeProduct =false, includeSupport =false, includeUpdates =false, ), itemsPerPage =null, itemsToSkip =null, next =null, query ="300", sortBy =null, sortDirection = SortDirection.ascending, ), user).orThrow()/*PageV2( items = listOf(ExampleResource( createdAt = 1635170395571, id = "3", owner = ResourceOwner( createdBy = "user", project = null, ), permissions = ResourcePermissions( myself = listOf(Permission.ADMIN), others = emptyList(), ), specification = ExampleResource.Spec( product = ProductReference( category = "example-compute", id = "example-compute", provider = "example", ), start = 0, target = 300, ), status = ExampleResource.Status( resolvedProduct = null, resolvedSupport = null, state = State.RUNNING, value = 10, ), updates = emptyList(), providerGeneratedId = "3", )), itemsPerPage = 50, next = null, )*/
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 discover the search functionality of resources. Search allows for free-text# queries which attempts to find relevant results. This is very different from browse with filters, # since 'relevancy' is a vaguely defined concept. Search is not guaranteed to return results in any# deterministic fashion, unlike browse.# We start with the following dataset.# Authenticated as usercurl -XGET -H "Authorization: Bearer $accessToken" "$host/api/example/browse?filterState=RUNNING&includeOthers=false&includeUpdates=false&includeSupport=false&includeProduct=false"
# {# "itemsPerPage": 50,# "items": [# {# "id": "1",# "specification": {# "start": 0,# "target": 100,# "product": {# "id": "example-compute",# "category": "example-compute",# "provider": "example"# }# },# "createdAt": 1635170395571,# "status": {# "state": "RUNNING",# "value": 10,# "resolvedSupport": null,# "resolvedProduct": null# },# "updates": [# ],# "owner": {# "createdBy": "user",# "project": null# },# "permissions": {# "myself": [# "ADMIN"# ],# "others": [# ]# }# },# {# "id": "2",# "specification": {# "start": 0,# "target": 200,# "product": {# "id": "example-compute",# "category": "example-compute",# "provider": "example"# }# },# "createdAt": 1635170395571,# "status": {# "state": "RUNNING",# "value": 10,# "resolvedSupport": null,# "resolvedProduct": null# },# "updates": [# ],# "owner": {# "createdBy": "user",# "project": null# },# "permissions": {# "myself": [# "ADMIN"# ],# "others": [# ]# }# },# {# "id": "3",# "specification": {# "start": 0,# "target": 300,# "product": {# "id": "example-compute",# "category": "example-compute",# "provider": "example"# }# },# "createdAt": 1635170395571,# "status": {# "state": "RUNNING",# "value": 10,# "resolvedSupport": null,# "resolvedProduct": null# },# "updates": [# ],# "owner": {# "createdBy": "user",# "project": null# },# "permissions": {# "myself": [# "ADMIN"# ],# "others": [# ]# }# }# ],# "next": null# }# Search may look in many different fields to determine if a result is relevant. Searching for the# value 300 might produce the following results.curl -XPOST -H "Authorization: Bearer $accessToken" -H "Content-Type: content-type: application/json; charset=utf-8" "$host/api/example/search" -d '{
"flags":{"filterState":null,"includeOthers":false,"includeUpdates":false,"includeSupport":false,"includeProduct":false,"filterCreatedBy":null,"filterCreatedAfter":null,"filterCreatedBefore":null,"filterProvider":null,"filterProductId":null,"filterProductCategory":null,"filterProviderIds":null,"filterIds":null,"hideProductId":null,"hideProductCategory":null,"hideProvider":null },"query":"300","itemsPerPage":null,"next":null,"consistency":null,"itemsToSkip":null,"sortBy":null,"sortDirection":"ascending"}'# {# "itemsPerPage": 50,# "items": [# {# "id": "3",# "specification": {# "start": 0,# "target": 300,# "product": {# "id": "example-compute",# "category": "example-compute",# "provider": "example"# }# },# "createdAt": 1635170395571,# "status": {# "state": "RUNNING",# "value": 10,# "resolvedSupport": null,# "resolvedProduct": null# },# "updates": [# ],# "owner": {# "createdBy": "user",# "project": null# },# "permissions": {# "myself": [# "ADMIN"# ],# "others": [# ]# }# }# ],# "next": null# }
Communication Flow: Visual
Example: Feature detection (Supported)
Frequency of use
Common
Actors
An authenticated user (user)
Communication Flow: Kotlin
/* In this example, we will show how to use the feature detection feature of resources. Recall, thatproviders need to specify if they support counting backwards. */Resources.retrieveProducts.call( Unit, user).orThrow()/*SupportByProvider( productsByProvider = mapOf("example" to listOf(ResolvedSupport( product = Product.Compute( allowAllocationRequestsFrom = AllocationRequestsGroup.ALL, category = ProductCategoryId( id = "example-compute", name = "example-compute", provider = "example", ), chargeType = ChargeType.ABSOLUTE, cpu = 1, cpuModel = null, description = "An example machine", freeToUse = false, gpu = null, gpuModel = null, hiddenInGrantApplications = false, memoryInGigs = 1, memoryModel = null, name = "example-compute", pricePerUnit = 1, priority = 0, productType = ProductType.COMPUTE, unitOfPrice = ProductPriceUnit.UNITS_PER_HOUR, version = 1, balance = null, id = "example-compute", maxUsableBalance = null, ), support = ExampleResourceSupport( maintenance = null, product = ProductReference( category = "example-compute", id = "example-compute", provider = "example", ), supportsBackwardsCounting = Supported.SUPPORTED, ), ))), )*//* In this case, the provider supports counting backwards. *//* Creating a resource which counts backwards should succeed. */Resources.create.call(bulkRequestOf(ExampleResource.Spec( product =ProductReference( category ="example-compute", id ="example-compute", provider ="example", ), start =0, target =-100, )), user).orThrow()/*BulkResponse( responses = listOf(FindByStringId( id = "1234", )), )*/
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 how to use the feature detection feature of resources. Recall, that# providers need to specify if they support counting backwards.# Authenticated as usercurl-XGET-H"Authorization: Bearer $accessToken""$host/api/example/retrieveProducts"# {# "productsByProvider": {# "example": [# {# "product": {# "type": "compute",# "balance": null,# "maxUsableBalance": null,# "name": "example-compute",# "pricePerUnit": 1,# "category": {# "name": "example-compute",# "provider": "example"# },# "description": "An example machine",# "priority": 0,# "cpu": 1,# "memoryInGigs": 1,# "gpu": null,# "cpuModel": null,# "memoryModel": null,# "gpuModel": null,# "version": 1,# "freeToUse": false,# "allowAllocationRequestsFrom": "ALL",# "unitOfPrice": "UNITS_PER_HOUR",# "chargeType": "ABSOLUTE",# "hiddenInGrantApplications": false,# "productType": "COMPUTE"# },# "support": {# "product": {# "id": "example-compute",# "category": "example-compute",# "provider": "example"# },# "supportsBackwardsCounting": "SUPPORTED",# "maintenance": null# }# }# ]# }# }# In this case, the provider supports counting backwards.# Creating a resource which counts backwards should succeed.curl -XPOST -H "Authorization: Bearer $accessToken" -H "Content-Type: content-type: application/json; charset=utf-8" "$host/api/example" -d '{
"items": [ {"start":0,"target":-100,"product":{"id":"example-compute","category":"example-compute","provider":"example" } } ]}'# {# "responses": [# {# "id": "1234"# }# ]# }
Communication Flow: Visual
Example: Feature detection (Failure scenario)
Frequency of use
Common
Actors
An authenticated user (user)
Communication Flow: Kotlin
/* In this example, we will show how to use the feature detection feature of resources. Recall, thatproviders need to specify if they support counting backwards. */Resources.retrieveProducts.call( Unit, user).orThrow()/*SupportByProvider( productsByProvider = mapOf("example" to listOf(ResolvedSupport( product = Product.Compute( allowAllocationRequestsFrom = AllocationRequestsGroup.ALL, category = ProductCategoryId( id = "example-compute", name = "example-compute", provider = "example", ), chargeType = ChargeType.ABSOLUTE, cpu = 1, cpuModel = null, description = "An example machine", freeToUse = false, gpu = null, gpuModel = null, hiddenInGrantApplications = false, memoryInGigs = 1, memoryModel = null, name = "example-compute", pricePerUnit = 1, priority = 0, productType = ProductType.COMPUTE, unitOfPrice = ProductPriceUnit.UNITS_PER_HOUR, version = 1, balance = null, id = "example-compute", maxUsableBalance = null, ), support = ExampleResourceSupport( maintenance = null, product = ProductReference( category = "example-compute", id = "example-compute", provider = "example", ), supportsBackwardsCounting = Supported.NOT_SUPPORTED, ), ))), )*//* In this case, the provider does not support counting backwards. *//* Creating a resource which counts backwards should fail. */Resources.create.call(bulkRequestOf(ExampleResource.Spec( product =ProductReference( category ="example-compute", id ="example-compute", provider ="example", ), start =0, target =-100, )), user).orThrow()/*400 Bad Request*/
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 how to use the feature detection feature of resources. Recall, that# providers need to specify if they support counting backwards.# Authenticated as usercurl-XGET-H"Authorization: Bearer $accessToken""$host/api/example/retrieveProducts"# {# "productsByProvider": {# "example": [# {# "product": {# "type": "compute",# "balance": null,# "maxUsableBalance": null,# "name": "example-compute",# "pricePerUnit": 1,# "category": {# "name": "example-compute",# "provider": "example"# },# "description": "An example machine",# "priority": 0,# "cpu": 1,# "memoryInGigs": 1,# "gpu": null,# "cpuModel": null,# "memoryModel": null,# "gpuModel": null,# "version": 1,# "freeToUse": false,# "allowAllocationRequestsFrom": "ALL",# "unitOfPrice": "UNITS_PER_HOUR",# "chargeType": "ABSOLUTE",# "hiddenInGrantApplications": false,# "productType": "COMPUTE"# },# "support": {# "product": {# "id": "example-compute",# "category": "example-compute",# "provider": "example"# },# "supportsBackwardsCounting": "NOT_SUPPORTED",# "maintenance": null# }# }# ]# }# }# In this case, the provider does not support counting backwards.# Creating a resource which counts backwards should fail.curl -XPOST -H "Authorization: Bearer $accessToken" -H "Content-Type: content-type: application/json; charset=utf-8" "$host/api/example" -d '{
"items": [ {"start":0,"target":-100,"product":{"id":"example-compute","category":"example-compute","provider":"example" } } ]}'# 400 Bad Request
Communication Flow: Visual
Example: Resource Collaboration
Frequency of use
Common
Actors
A UCloud user named Alice (alice)
A UCloud user named Bob (bob)
Communication Flow: Kotlin
/* In this example, we discover how to use the resource collaboration features of UCloud. This exampleinvolves two users: Alice and Bob. *//* Alice starts by creating a resource */Resources.create.call(bulkRequestOf(ExampleResource.Spec( product =ProductReference( category ="example-compute", id ="example-compute", provider ="example", ), start =0, target =100, )), alice).orThrow()/*BulkResponse( responses = listOf(FindByStringId( id = "1234", )), )*//* By default, Bob doesn't have access to this resource. Attempting to retrieve it will fail. */Resources.retrieve.call(ResourceRetrieveRequest( flags =ExampleResourceFlags( filterCreatedAfter =null, filterCreatedBefore =null, filterCreatedBy =null, filterIds =null, filterProductCategory =null, filterProductId =null, filterProvider =null, filterProviderIds =null, filterState =null, hideProductCategory =null, hideProductId =null, hideProvider =null, includeOthers =false, includeProduct =false, includeSupport =false, includeUpdates =false, ), id ="1234", ), bob).orThrow()/*404 Not Found*//* Alice can change the permissions of the resource by invoking updateAcl. This causes Bob to gain READ permissions. */Resources.updateAcl.call(bulkRequestOf(UpdatedAcl( added =listOf(ResourceAclEntry( entity = AclEntity.ProjectGroup( group ="Group of Bob", projectId ="Project", ), permissions =listOf(Permission.READ), )), deleted =emptyList(), id ="1234", )), alice).orThrow()/*BulkResponse( responses = listOf(Unit), )*//* Bob can now retrieve the resource. */Resources.retrieve.call(ResourceRetrieveRequest( flags =ExampleResourceFlags( filterCreatedAfter =null, filterCreatedBefore =null, filterCreatedBy =null, filterIds =null, filterProductCategory =null, filterProductId =null, filterProvider =null, filterProviderIds =null, filterState =null, hideProductCategory =null, hideProductId =null, hideProvider =null, includeOthers =false, includeProduct =false, includeSupport =false, includeUpdates =false, ), id ="1234", ), bob).orThrow()/*ExampleResource( createdAt = 1635170395571, id = "1234", owner = ResourceOwner( createdBy = "user", project = null, ), permissions = ResourcePermissions( myself = listOf(Permission.READ), others = emptyList(), ), specification = ExampleResource.Spec( product = ProductReference( category = "example-compute", id = "example-compute", provider = "example", ), start = 0, target = 100, ), status = ExampleResource.Status( resolvedProduct = null, resolvedSupport = null, state = State.RUNNING, value = 10, ), updates = listOf(ExampleResource.Update( currentValue = null, newState = State.PENDING, status = "We are about to start counting!", timestamp = 1635170395571, ), ExampleResource.Update( currentValue = 10, newState = State.RUNNING, status = "We are now counting!", timestamp = 1635170395571, )), providerGeneratedId = "1234", )*/
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 discover how to use the resource collaboration features of UCloud. This example# involves two users: Alice and Bob.# Alice starts by creating a resource# Authenticated as alicecurl -XPOST -H "Authorization: Bearer $accessToken" -H "Content-Type: content-type: application/json; charset=utf-8" "$host/api/example" -d '{
"items": [ {"start":0,"target":100,"product":{"id":"example-compute","category":"example-compute","provider":"example" } } ]}'# {# "responses": [# {# "id": "1234"# }# ]# }# By default, Bob doesn't have access to this resource. Attempting to retrieve it will fail.# Authenticated as bobcurl -XGET -H "Authorization: Bearer $accessToken" "$host/api/example/retrieve?includeOthers=false&includeUpdates=false&includeSupport=false&includeProduct=false&id=1234"
# 404 Not Found# Alice can change the permissions of the resource by invoking updateAcl. This causes Bob to gain READ permissions.# Authenticated as alicecurl -XPOST -H "Authorization: Bearer $accessToken" -H "Content-Type: content-type: application/json; charset=utf-8" "$host/api/example/updateAcl" -d '{
"items": [ {"id":"1234","added": [ {"entity":{"type":"project_group","projectId":"Project","group":"Group of Bob" },"permissions": ["READ" ] } ],"deleted": [ ] } ]}'# {# "responses": [# {# }# ]# }# Bob can now retrieve the resource.# Authenticated as bobcurl -XGET -H "Authorization: Bearer $accessToken" "$host/api/example/retrieve?includeOthers=false&includeUpdates=false&includeSupport=false&includeProduct=false&id=1234"
# {# "id": "1234",# "specification": {# "start": 0,# "target": 100,# "product": {# "id": "example-compute",# "category": "example-compute",# "provider": "example"# }# },# "createdAt": 1635170395571,# "status": {# "state": "RUNNING",# "value": 10,# "resolvedSupport": null,# "resolvedProduct": null# },# "updates": [# {# "timestamp": 1635170395571,# "status": "We are about to start counting!",# "newState": "PENDING",# "currentValue": null# },# {# "timestamp": 1635170395571,# "status": "We are now counting!",# "newState": "RUNNING",# "currentValue": 10# }# ],# "owner": {# "createdBy": "user",# "project": null# },# "permissions": {# "myself": [# "READ"# ],# "others": [# ]# }# }
This endpoint will determine all providers that which the authenticated user has access to, in the current workspace. A user has access to a product, and thus a provider, if the product is either free or if the user has been granted credits to use the product.
This request is sent by the client, if the client believes that initialization of resources might be needed. NOTE: This request might be sent even if initialization has already taken place. UCloud/Core does not check if initialization has already taken place, it simply validates the request.
The contents of this field depends almost entirely on the specific Resource that this field is managing. Typically, this will contain information such as:
A state value. For example, a compute Job might be RUNNING
Key metrics about the resource.
Related resources. For example, certain Resources are bound to another Resource in a mutually exclusive way, this should be listed in the status section.
Updates can optionally be fetched for a Resource. The updates describe how the Resource changes state over time. The current state of a Resource can typically be read from its status field. Thus, it is typically not needed to use the full update history if you only wish to know the current state of a Resource.
An update will typically contain information similar to the status field, for example:
A state value. For example, a compute Job might be RUNNING.
This type covers the permission part of UCloud's RBAC based authorization model. UCloud defines a set of standard permissions that can be applied to a resource and its associated operations.