Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds Nexus Endpoint #23

Merged
merged 26 commits into from
Aug 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 96 additions & 2 deletions temporal/api/cloud/cloudservice/v1/request_response.proto
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ option csharp_namespace = "Temporalio.Api.Cloud.CloudService.V1";
import "temporal/api/cloud/operation/v1/message.proto";
import "temporal/api/cloud/identity/v1/message.proto";
import "temporal/api/cloud/namespace/v1/message.proto";
import "temporal/api/cloud/nexus/v1/message.proto";
import "temporal/api/cloud/region/v1/message.proto";

message GetUsersRequest {
Expand Down Expand Up @@ -269,7 +270,6 @@ message GetRegionResponse {
temporal.api.cloud.region.v1.Region region = 1;
}


message GetApiKeysRequest {
// The requested size of the page to retrieve - optional.
// Cannot exceed 1000. Defaults to 100.
Expand All @@ -286,6 +286,7 @@ message GetApiKeysRequest {
message GetApiKeysResponse {
// The list of api keys in ascending id order.
repeated temporal.api.cloud.identity.v1.ApiKey api_keys = 1;

// The next page's token.
string next_page_token = 2;
}
Expand All @@ -304,14 +305,15 @@ message CreateApiKeyRequest {
// The spec for the api key to create.
// Create api key only supports service-account owner type for now.
temporal.api.cloud.identity.v1.ApiKeySpec spec = 1;

// The id to use for this async operation - optional.
string async_operation_id = 2;
}

message CreateApiKeyResponse {
// The id of the api key created.
string key_id = 1;
// The token of the api key created.
// The token of the api key created.
// This is a secret and should be stored securely.
// It will not be retrievable after this response.
string token = 2;
Expand All @@ -327,6 +329,7 @@ message UpdateApiKeyRequest {
// The version of the api key for which this update is intended for.
// The latest version can be found in the GetApiKey operation response.
string resource_version = 3;

// The id to use for this async operation - optional.
string async_operation_id = 4;
}
Expand All @@ -342,6 +345,7 @@ message DeleteApiKeyRequest {
// The version of the api key for which this delete is intended for.
// The latest version can be found in the GetApiKey operation response.
string resource_version = 2;

// The id to use for this async operation - optional.
string async_operation_id = 3;
}
Expand All @@ -351,6 +355,95 @@ message DeleteApiKeyResponse {
temporal.api.cloud.operation.v1.AsyncOperation async_operation = 1;
}

message GetNexusEndpointsRequest {
// The requested size of the page to retrieve - optional.
// Cannot exceed 1000. Defaults to 100.
int32 page_size = 1;

// The page token if this is continuing from another response - optional.
string page_token = 2;

// optional, treated as an AND if specified
string target_namespace_id = 3;

// optional, treated as an AND if specified
string target_task_queue = 4;

bergundy marked this conversation as resolved.
Show resolved Hide resolved
// Filter endpoints by their name - optional, treated as an AND if specified. Specifying this will result in zero or one results.
string name = 5;
}

message GetNexusEndpointsResponse {
// The list of endpoints in ascending id order.
repeated temporal.api.cloud.nexus.v1.Endpoint endpoints = 1;

// The next page's token.
string next_page_token = 2;
}

message GetNexusEndpointRequest {
// The id of the nexus endpoint to get.
string endpoint_id = 1;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can just call this id, that's what I did in the operator API.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so I changed this to id, but this is now in-consistent with our other APIs related to user and namespace operations (where the request/path takes in user_id or namespace_id). am fine with having this as id, but will check with @anekkanti to be sure

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to be consistent with the rest of the API here, that is more important than consistency with the self-hosted operator service

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed it back

}

message GetNexusEndpointResponse {
// The nexus endpoint.
temporal.api.cloud.nexus.v1.Endpoint endpoint = 1;
}

message CreateNexusEndpointRequest {
// The spec for the nexus endpoint.
temporal.api.cloud.nexus.v1.EndpointSpec spec = 1;

// The id to use for this async operation - optional.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have guidance anywhere explaining why you'd want to specify this? I understand the concept but I'm not sure users do.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree that this probably needs to be fleshed out more here: https://docs.temporal.io/ops. The API itself is still in preview. I have seen other APIs have a section about "idempotency" which describes the usage/semantics around similar fields. We may want something similar her.

cc @anekkanti @jlacefie in case there is some other documentation I am missing here, or to potentially track ensuring docs cover this eventually

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rachfop since he is working on docs

string async_operation_id = 2;
}

message CreateNexusEndpointResponse {
// The id of the endpoint that was created.
string endpoint_id = 1;

// The async operation.
temporal.api.cloud.operation.v1.AsyncOperation async_operation = 2;
}

message UpdateNexusEndpointRequest {
// The id of the nexus endpoint to update.
string endpoint_id = 1;

// The updated nexus endpoint specification.
temporal.api.cloud.nexus.v1.EndpointSpec spec = 2;

// The version of the nexus endpoint for which this update is intended for.
// The latest version can be found in the GetNexusEndpoint operation response.
string resource_version = 3;

// The id to use for this async operation - optional.
string async_operation_id = 4;
}

message UpdateNexusEndpointResponse {
// The async operation.
temporal.api.cloud.operation.v1.AsyncOperation async_operation = 1;
}

message DeleteNexusEndpointRequest {
// The id of the nexus endpoint to delete.
string endpoint_id = 1;

// The version of the endpoint for which this delete is intended for.
// The latest version can be found in the GetNexusEndpoint operation response.
string resource_version = 2;

// The id to use for this async operation - optional.
string async_operation_id = 3;
}

message DeleteNexusEndpointResponse {
// The async operation
temporal.api.cloud.operation.v1.AsyncOperation async_operation = 1;
}

message GetUserGroupsRequest {
// The requested size of the page to retrieve - optional.
// Cannot exceed 1000. Defaults to 100.
Expand Down Expand Up @@ -398,6 +491,7 @@ message CreateUserGroupRequest {
message CreateUserGroupResponse {
// The id of the group that was created.
string group_id = 1;

// The async operation.
temporal.api.cloud.operation.v1.AsyncOperation async_operation = 2;
}
Expand Down
37 changes: 37 additions & 0 deletions temporal/api/cloud/cloudservice/v1/service.proto
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,43 @@ service CloudService {
};
}

// Gets nexus endpoints
rpc GetNexusEndpoints(GetNexusEndpointsRequest) returns (GetNexusEndpointsResponse) {
option (google.api.http) = {
get: "/cloud/nexus/endpoints",
};
}

// Get a nexus endpoint
rpc GetNexusEndpoint(GetNexusEndpointRequest) returns (GetNexusEndpointResponse) {
option (google.api.http) = {
get: "/cloud/nexus/endpoints/{endpoint_id}",
};
}

// Create a nexus endpoint
rpc CreateNexusEndpoint(CreateNexusEndpointRequest) returns (CreateNexusEndpointResponse) {
option (google.api.http) = {
post: "/cloud/nexus/endpoints",
body: "*"
};
}

// Update a nexus endpoint
rpc UpdateNexusEndpoint(UpdateNexusEndpointRequest) returns (UpdateNexusEndpointResponse) {
option (google.api.http) = {
post: "/cloud/nexus/endpoints/{endpoint_id}",
body: "*"
};
}

// Delete a nexus endpoint
rpc DeleteNexusEndpoint(DeleteNexusEndpointRequest) returns (DeleteNexusEndpointResponse) {
option (google.api.http) = {
delete: "/cloud/nexus/endpoints/{endpoint_id}",
};
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
}
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it time to add a formatter?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that can be discussed on the primary api repo and can apply to this if/when it moves there


// Get all user groups
rpc GetUserGroups (GetUserGroupsRequest) returns (GetUserGroupsResponse) {
option (google.api.http) = {
Expand Down
79 changes: 79 additions & 0 deletions temporal/api/cloud/nexus/v1/message.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
syntax = "proto3";

package temporal.api.cloud.nexus.v1;

option go_package = "go.temporal.io/api/cloud/nexus/v1;nexus";

import "temporal/api/cloud/resource/v1/message.proto";
import "google/protobuf/timestamp.proto";

message EndpointSpec {
// The name of the endpoint. Must be unique within an account.
// The name must match `^[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9]$`.
// This field is mutable.
string name = 1;

// Indicates where the endpoint should forward received nexus requests to.
EndpointTargetSpec target_spec = 2;

// The set of policies (e.g. authorization) for the endpoint. Each request's caller
// must match with at least one of the specs to be accepted by the endpoint.
// This field is mutable.
repeated EndpointPolicySpec policy_specs = 3;

// The markdown description of the endpoint - optional.
string description = 4;
mastermanu marked this conversation as resolved.
Show resolved Hide resolved
}

message EndpointTargetSpec {
oneof variant {
// A target spec for routing nexus requests to a specific cloud namespace worker.
WorkerTargetSpec worker_target_spec = 1;
}
}

message WorkerTargetSpec {
// The target cloud namespace to route requests to. Namespace must be in same account as the endpoint. This field is mutable.
string namespace_id = 1;

// The task queue on the cloud namespace to route requests to. This field is mutable.
string task_queue = 2;
}

message EndpointPolicySpec {
oneof variant {
// A policy spec that allows one caller namespace to access the endpoint.
AllowedCloudNamespacePolicySpec allowed_cloud_namespace_policy_spec = 1;
}
}

message AllowedCloudNamespacePolicySpec {
// The namespace that is allowed to call into this endpoint. Calling namespace must be in same account as the endpoint.
string namespace_id = 1;
}

// An endpoint that receives and then routes Nexus requests
message Endpoint {
// The id of the endpoint. This is generated by the server and is immutable.
string id = 1;

// The current version of the endpoint specification.
// The next update operation must include this version.
string resource_version = 2;

// The endpoint specification.
EndpointSpec spec = 3;

// The current state of the endpoint.
// For any failed state, reach out to Temporal Cloud support for remediation.
temporal.api.cloud.resource.v1.ResourceState state = 4;

// The id of any ongoing async operation that is creating, updating, or deleting the endpoint, if any.
string async_operation_id = 5;

// The date and time when the endpoint was created.
google.protobuf.Timestamp created_time = 6;

// The date and time when the endpoint was last modified.
google.protobuf.Timestamp last_modified_time = 7;
Comment on lines +74 to +78
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mastermanu can we also show the identity that created and modified this endpoint?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think we can, although we'd probably want to consider adding that across all the objects we have (e.g. users, namespaces, etc).

would probably consider adding that as a separate effort.

}
25 changes: 25 additions & 0 deletions temporal/api/cloud/resource/v1/message.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
syntax = "proto3";

package temporal.api.cloud.resource.v1;

option go_package = "go.temporal.io/api/cloud/resource/v1;resource";
option java_package = "io.temporal.api.cloud.resource.v1";
option java_multiple_files = true;
option java_outer_classname = "MessageProto";
option ruby_package = "Temporalio::Api::Cloud::Resource::V1";
option csharp_namespace = "Temporalio.Api.Cloud.Resource.V1";


enum ResourceState {
RESOURCE_STATE_UNSPECIFIED = 0;
RESOURCE_STATE_ACTIVATING = 1; // The resource is being activated.
RESOURCE_STATE_ACTIVATION_FAILED = 2; // The resource failed to activate. This is an error state. Reach out to support for remediation.
RESOURCE_STATE_ACTIVE = 3; // The resource is active and ready to use.
RESOURCE_STATE_UPDATING = 4; // The resource is being updated.
RESOURCE_STATE_UPDATE_FAILED = 5; // The resource failed to update. This is an error state. Reach out to support for remediation.
RESOURCE_STATE_DELETING = 6; // The resource is being deleted.
RESOURCE_STATE_DELETE_FAILED = 7; // The resource failed to delete. This is an error state. Reach out to support for remediation.
RESOURCE_STATE_DELETED = 8; // The resource has been deleted.
RESOURCE_STATE_SUSPENDED = 9; // The resource is suspended and not available for use. Reach out to support for remediation.
RESOURCE_STATE_EXPIRED = 10; // The resource has expired and is no longer available for use.
}