resources

« Previous section Next section »

UCloud Developer Guide / Orchestration of Resources / Introduction to Resources

Introduction to Resources

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.

Table of Contents

1. Examples

2. Remote Procedure Calls

3. Data Models

Example: Browsing the catalog

Frequency of useCommon

Actors

  • An authenticated user (user)

Communication Flow: Kotlin

/* 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. */

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 the
current 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 user
curl -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 useCommon

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 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. */

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 user
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"
#         }
#     ]
# }

# 📝 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 useCommon

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 user
curl -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 useCommon

Actors

  • An authenticated user (user)

Communication Flow: Kotlin

/* 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. */

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 the
value 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 user
curl -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 useCommon

Actors

  • An authenticated user (user)

Communication Flow: Kotlin

/* 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. */

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 user
curl -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 useCommon

Actors

  • An authenticated user (user)

Communication Flow: Kotlin

/* 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. */

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 user
curl -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 useCommon

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 example
involves 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 alice
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"
#         }
#     ]
# }

# By default, Bob doesn't have access to this resource. Attempting to retrieve it will fail.

# Authenticated as bob
curl -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 alice
curl -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 bob
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": [
#             "READ"
#         ],
#         "others": [
#         ]
#     }
# }
Communication Flow: Visual

Remote Procedure Calls

browse

Browses the catalog of available resources

retrieve

Retrieve a single resource

retrieveProducts

Retrieve product support for all accessible providers

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.

See also:

Searches the catalog of available resources

create

Creates one or more resources

delete

Deletes one or more resources

init

Request (potential) initialization of resources

RequestResponseError

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.

updateAcl

Updates the ACL attached to a resource

Data Models

Maintenance

data class Maintenance(
    val description: String,
    val availability: Maintenance.Availability,
    val startsAt: Long,
    val estimatedEndsAt: Long?,
)
Properties


Maintenance.Availability

enum class Availability {
    MINOR_DISRUPTION,
    MAJOR_DISRUPTION,
    NO_SERVICE,
}
Properties


ResolvedSupport

data class ResolvedSupport<P, Support>(
    val product: P,
    val support: Support,
)
Properties


ResourceChargeCredits

data class ResourceChargeCredits(
    val id: String,
    val chargeId: String,
    val units: Long,
    val periods: Long?,
    val performedBy: String?,
    val description: String?,
)
Properties


SortDirection

enum class SortDirection {
    ascending,
    descending,
}
Properties


SupportByProvider

data class SupportByProvider<P, S>(
    val productsByProvider: JsonObject,
)
Properties


AclEntity

sealed class AclEntity {
    class ProjectGroup : AclEntity()
    class User : AclEntity()
}

AclEntity.ProjectGroup

data class ProjectGroup(
    val projectId: String,
    val group: String,
    val type: String /* "project_group" */,
)
Properties


AclEntity.User

data class User(
    val username: String,
    val type: String /* "user" */,
)
Properties


ExampleResource

A Resource is the core data model used to synchronize tasks between UCloud and Provider.

data class ExampleResource(
    val id: String,
    val specification: ExampleResource.Spec,
    val createdAt: Long,
    val status: ExampleResource.Status,
    val updates: List<ExampleResource.Update>,
    val owner: ResourceOwner,
    val permissions: ResourcePermissions?,
    val providerGeneratedId: String?,
)

For more information go here.

Properties


ExampleResource.Spec

data class Spec(
    val start: Int,
    val target: Int,
    val product: ProductReference,
)
Properties


ExampleResource.State

enum class State {
    PENDING,
    RUNNING,
    DONE,
}
Properties


ExampleResource.Status

Describes the current state of the Resource

data class Status(
    val state: ExampleResource.State,
    val value: Int,
    val resolvedSupport: ResolvedSupport<Product, ExampleResourceSupport>?,
    val resolvedProduct: Product?,
)

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.

Properties


ExampleResource.Update

Describes an update to the Resource

data class Update(
    val timestamp: Long?,
    val status: String?,
    val newState: ExampleResource.State?,
    val currentValue: Int?,
)

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.

  • Change in key metrics.

  • Bindings to related Resources.

Properties


ExampleResourceFlags

data class ExampleResourceFlags(
    val filterState: ExampleResource.State?,
    val includeOthers: Boolean?,
    val includeUpdates: Boolean?,
    val includeSupport: Boolean?,
    val includeProduct: Boolean?,
    val filterCreatedBy: String?,
    val filterCreatedAfter: Long?,
    val filterCreatedBefore: Long?,
    val filterProvider: String?,
    val filterProductId: String?,
    val filterProductCategory: String?,
    val filterProviderIds: String?,
    val filterIds: String?,
    val hideProductId: String?,
    val hideProductCategory: String?,
    val hideProvider: String?,
)
Properties


ExampleResourceSupport

data class ExampleResourceSupport(
    val product: ProductReference,
    val supportsBackwardsCounting: ExampleResourceSupport.Supported?,
    val maintenance: Maintenance?,
)
Properties


ExampleResourceSupport.Supported

enum class Supported {
    SUPPORTED,
    NOT_SUPPORTED,
}
Properties


Permission

The UCloud permission model

enum class Permission {
    READ,
    EDIT,
    ADMIN,
    PROVIDER,
}

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.

Properties


ResourceAclEntry

data class ResourceAclEntry(
    val entity: AclEntity,
    val permissions: List<Permission>,
)
Properties


ResourceUpdateAndId

data class ResourceUpdateAndId<U>(
    val id: String,
    val update: U,
)
Properties


UpdatedAclWithResource

data class UpdatedAclWithResource<Res>(
    val resource: Res,
    val added: List<ResourceAclEntry>,
    val deleted: List<AclEntity>,
)
Properties


ResourceBrowseRequest

data class ResourceBrowseRequest<Flags>(
    val flags: Flags,
    val itemsPerPage: Int?,
    val next: String?,
    val consistency: PaginationRequestV2Consistency?,
    val itemsToSkip: Long?,
    val sortBy: String?,
    val sortDirection: SortDirection?,
)
Properties


ResourceInitializationRequest

data class ResourceInitializationRequest(
    val principal: ResourceOwner,
)
Properties


ResourceRetrieveRequest

data class ResourceRetrieveRequest<Flags>(
    val flags: Flags,
    val id: String,
)
Properties


ResourceSearchRequest

data class ResourceSearchRequest<Flags>(
    val flags: Flags,
    val query: String,
    val itemsPerPage: Int?,
    val next: String?,
    val consistency: PaginationRequestV2Consistency?,
    val itemsToSkip: Long?,
    val sortBy: String?,
    val sortDirection: SortDirection?,
)
Properties


ResourceChargeCreditsResponse

data class ResourceChargeCreditsResponse(
    val insufficientFunds: List<FindByStringId>,
    val duplicateCharges: List<FindByStringId>,
)
Properties


Last updated