Skip to content

Commit

Permalink
[public-api] Draft more of the prebuild API
Browse files Browse the repository at this point in the history
  • Loading branch information
csweichel committed Mar 19, 2022
1 parent 46f5ab6 commit f8edb19
Show file tree
Hide file tree
Showing 14 changed files with 4,403 additions and 1,110 deletions.
97 changes: 1 addition & 96 deletions components/public-api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,99 +3,4 @@
# Example Flows
This section gives examples how clients would use this API.

## Create Workspace

### Not prebuild aware
```go
workspaces.CreateWorkspace({
idempotency_token: "<random_string>",
context_url: "https://github.com/gitpod-io/gitpod",
})
```

### Prebuild aware but no log support
```go
workspaces.CreateWorkspace({
idempotency_token: "<random_string>",
context_url: "https://github.com/gitpod-io/gitpod",
prebuild: {
if_available: true,
}
})
```

### Prebuild aware with log support
```go
contextURL := "https://github.com/gitpod-io/gitpod"
prb := prebuilds.GetRunningPrebuild({ context_url: contextURL })
logs := prebuilds.ListenToPrebuild({ context_url: contextURL, prebuild_id: prb.PrebuildID })

for logs.Recv() {
// display logs
}
// once logs are done, prebuild is done (errors notwithstanding)

workspaces.CreateWorkspace({
idempotency_token: "<random_string>",
context_url: contextURL,
prebuild: {
prebuild_id: prb.PrebuildID,
}
})
```

## Start Workspace

### Ignoring image-build logs
```Go
// Get ahold of a workspace ID, either by finding an existing workspace
// or creating a new one.
workspaceID := ...

// Start the workspace
workspaces.StartWorkspace({
idempotency_token: "<random_string>",
workspace_id: workspaceID,
})
```

### With image build log support
```Go
// Get ahold of a workspace ID, either by finding an existing workspace
// or creating a new one.
workspaceID := ...

// Start the workspace
resp := workspaces.StartWorkspace({
idempotency_token: "<random_string>",
workspace_id: workspaceID,
})

// Listen to updates for the instance we just created
updates := workspaces.ListenToWorkspaceInstance({
instance_id: resp.InstanceId
})
var lastSeenVersion uint64
for {
update := updates.Recv()
if lastSeenVersion == update.Version {
continue
}
lastSeenVersion = update.Version

switch update.Phase {
case ImageBuild:
go showImageBuildLogs(instanceID)
case Running:
// do something with this running workspace
}
}

func showImageBuildLogs(instanceID string) {
logs := workspaces.ListenToImageBuildLogs({instance_id: instanceID})
for {
resp := logs.Recv()
fmt.Println(resp.Line)
}
}
```
https://github.com/gitpod-io/gitpod/blob/094dde356a04740500175e8797462a48c3153c89/components/public-api/go/v1/examples_test.go#L20-L103
93 changes: 91 additions & 2 deletions components/public-api/gitpod/v1/prebuilds.proto
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ syntax = "proto3";

package gitpod.v1;

import "gitpod/v1/workspaces.proto";
import "google/rpc/status.proto";

option go_package = "github.com/gitpod-io/gitpod/public-api/v1";
Expand All @@ -10,19 +11,107 @@ option go_package = "github.com/gitpod-io/gitpod/public-api/v1";

service PrebuildsService {

// GetPrebuild retrieves a single rebuild.
// Errors:
// NOT_FOUND if the prebuild_id does not exist
rpc GetPrebuild(GetPrebuildRequest) returns (GetPrebuildResponse) {}

// GetRunningPrebuild returns the prebuild ID of a running prebuild,
// or NOT_FOUND if there is no prebuild running for the content_url.
rpc GetRunningPrebuild(GetRunningPrebuildRequest) returns (GetRunningPrebuildResponse) {}

// ListenToPrebuildStatus streams status updates for a prebuild. If the prebuild is already
// in the Done phase, only that single status is streamed.
rpc ListenToPrebuildStatus(ListenToPrebuildStatusRequest) returns (stream ListenToPrebuildStatusResponse) {}

// ListenToPrebuildLogs returns the log output of a prebuild.
// This does NOT include an image build if one happened.
rpc ListenToPrebuildLogs(ListenToPrebuildLogsRequest) returns (stream ListenToPrebuildLogsResponse) {}

}

message GetPrebuildRequest {
string prebuild_id = 1;
}
message GetPrebuildResponse {
google.rpc.Status response_status = 1;

Prebuild prebuild = 2;
}

message GetRunningPrebuildRequest {
string context_url = 1;
}

message GetRunningPrebuildResponse {
google.rpc.Status response_status = 1;

string prebuild_id = 2;
Prebuild prebuild = 2;
}

message ListenToPrebuildStatusRequest{
string prebuild_id = 1;
}
message ListenToPrebuildStatusResponse {
google.rpc.Status response_status = 1;

PrebuildStatus status = 2;
}

message ListenToPrebuildLogsRequest {
string prebuild_id = 1;
}
message ListenToPrebuildLogsResponse {
google.rpc.Status response_status = 1;

string line = 2;
}

////////////////////////////////
// Shared messages come here
////////////////////////////////

// Prebuild describes a prebuild
message Prebuild {
string prebuild_id = 1;
PrebuildSpec spec = 2;
PrebuildStatus status = 3;
}

// PrebuildSpec specifies the prebuild input.
message PrebuildSpec {
WorkspaceContext context = 1;

// Incremental prebuilds are based on other prebuilds. If this field is true,
// expect the context detail to point to another prebuild.
bool incremental = 2;
}

// PrebuildStatus describes the prebuild status.
message PrebuildStatus {
enum Phase {
PHASE_UNSPECIFIED = 0;
PHASE_PENDING = 1;
PHASE_RUNNING = 2;
PHASE_DONE = 3;
}
enum Result {
RESULT_UNSPECIFIED = 0;
RESULT_SUCCESS = 1;
RESULT_USER_CANCELED = 2;
RESULT_SYSTEM_FAILURE = 3;
RESULT_TASK_FAILURE = 4;
}

// Phase is the prebuild phase we're in
Phase phase = 1;

// Result indicates what result the prebuild produced, i.e. if it ran
// successfully or failed for some reason. If phase != done, this field
// will have RESULT_UNSPECIFIED as value.
Result result = 2;

// result_message contains a human readable message describing the prebuild
// result. E.g. if teh result is SYSTEM_FAILURE, the message describes what
// that failure was.
string result_message = 3;
}
132 changes: 63 additions & 69 deletions components/public-api/gitpod/v1/workspaces.proto
Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,9 @@ message GetWorkspaceResponse {
message CreateAndStartWorkspaceRequest {
string idempotency_token = 1;

string context_url = 2;

oneof prebuild {
// if true, and there's a prebuild available (not running), use that prebuild
bool if_available = 3;
// uses a particular prebuild - the prebuild ID is scoped by the context URL.
// Use the PrebuildService to get ahold of the prebuild_id.
string prebuild_id = 4;
oneof source {
string context_url = 2;
string prebuild_id = 3;
}

StartWorkspaceSpec start_spec = 5;
Expand Down Expand Up @@ -224,6 +219,64 @@ message WorkspaceInstance {

// WorkspaceStatus describes a workspace status
message WorkspaceInstanceStatus {
// Phase is a simple, high-level summary of where the workspace instance is in its lifecycle.
// The phase is not intended to be a comprehensive rollup of observations of the workspace state,
// nor is it intended to be a comprehensive state machine.
// (based on https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-phase)
enum Phase {
// Unknown indicates an issue within the workspace manager in that it cannot determine the actual phase of
// a workspace. This phase is usually accompanied by an error.
PHASE_UNSPECIFIED = 0;

// ImageBuild indicates that there's an image build running for this workspace.
PHASE_IMAGEBUILD = 1;

// Pending means the workspace does not yet consume resources in the cluster, but rather is looking for
// some space within the cluster. If for example the cluster needs to scale up to accomodate the
// workspace, the workspace will be in Pending state until that happened.
PHASE_PENDING = 2;

// Creating means the workspace is currently being created. That includes downloading the images required
// to run the workspace over the network. The time spent in this phase varies widely and depends on the current
// network speed, image size and cache states.
PHASE_CREATING = 3;

// Initializing is the phase in which the workspace is executing the appropriate workspace initializer (e.g. Git
// clone or backup download). After this phase one can expect the workspace to either be Running or Failed.
PHASE_INITIALIZING = 4;

// Running means the workspace is able to actively perform work, either by serving a user through Theia,
// or as a headless workspace.
PHASE_RUNNING = 5;

// Interrupted is an exceptional state where the container should be running but is temporarily unavailable.
// When in this state, we expect it to become running or stopping anytime soon.
PHASE_INTERRUPTED = 6;

// Stopping means that the workspace is currently shutting down. It could go to stopped every moment.
PHASE_STOPPING = 7;

// Stopped means the workspace ended regularly because it was shut down.
PHASE_STOPPED = 8;
}

// Conditions gives more detailed information as to the state of the workspace. Which condition actually
// has a value depends on the phase the workspace is in.
message Conditions {
// failed contains the reason the workspace failed to operate. If this field is empty, the workspace has not failed.
// This field is filled exclusively when caused by system errors.
string failed = 1;

// timeout contains the reason the workspace has timed out. If this field is empty, the workspace has not timed out.
string timeout = 2;

// first_user_activity is the time when MarkActive was first called on the workspace
google.protobuf.Timestamp first_user_activity = 9;

// stopped_by_request is true if the workspace was stopped using a StopWorkspace call
optional bool stopped_by_request = 11;
}

// version of the status update. Workspace instances themselves are unversioned,
// but their statuus has different versions.
// The value of this field has no semantic meaning (e.g. don't interpret it as
Expand All @@ -232,10 +285,10 @@ message WorkspaceInstanceStatus {
uint64 status_version = 1;

// the phase of a workspace is a simple, high-level summary of where the workspace instance is in its lifecycle
WorkspaceInstancePhase phase = 2;
Phase phase = 2;

// conditions detail the current state of the workspace instance
WorkspaceInstanceConditions conditions = 3;
Conditions conditions = 3;

// message is an optional human-readable message detailing the current phase
string message = 4;
Expand All @@ -252,65 +305,6 @@ message WorkspaceInstanceStatus {
// contentservice.GitStatus repo = 7;
}


// WorkspaceInstancePhase is a simple, high-level summary of where the workspace instance is in its lifecycle.
// The phase is not intended to be a comprehensive rollup of observations of the workspace state,
// nor is it intended to be a comprehensive state machine.
// (based on https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-phase)
enum WorkspaceInstancePhase {
// Unknown indicates an issue within the workspace manager in that it cannot determine the actual phase of
// a workspace. This phase is usually accompanied by an error.
WORKSPACE_INSTANCE_PHASE_UNSPECIFIED = 0;

// This will become IMAGE_BUILD
reserved 1;

// Pending means the workspace does not yet consume resources in the cluster, but rather is looking for
// some space within the cluster. If for example the cluster needs to scale up to accomodate the
// workspace, the workspace will be in Pending state until that happened.
WORKSPACE_INSTANCE_PHASE_PENDING = 2;

// Creating means the workspace is currently being created. That includes downloading the images required
// to run the workspace over the network. The time spent in this phase varies widely and depends on the current
// network speed, image size and cache states.
WORKSPACE_INSTANCE_PHASE_CREATING = 3;

// Initializing is the phase in which the workspace is executing the appropriate workspace initializer (e.g. Git
// clone or backup download). After this phase one can expect the workspace to either be Running or Failed.
WORKSPACE_INSTANCE_PHASE_INITIALIZING = 4;

// Running means the workspace is able to actively perform work, either by serving a user through Theia,
// or as a headless workspace.
WORKSPACE_INSTANCE_PHASE_RUNNING = 5;

// Interrupted is an exceptional state where the container should be running but is temporarily unavailable.
// When in this state, we expect it to become running or stopping anytime soon.
WORKSPACE_INSTANCE_PHASE_INTERRUPTED = 6;

// Stopping means that the workspace is currently shutting down. It could go to stopped every moment.
WORKSPACE_INSTANCE_PHASE_STOPPING = 7;

// Stopped means the workspace ended regularly because it was shut down.
WORKSPACE_INSTANCE_PHASE_STOPPED = 8;
}

// WorkspaceInstanceConditions gives more detailed information as to the state of the workspace. Which condition actually
// has a value depends on the phase the workspace is in.
message WorkspaceInstanceConditions {
// failed contains the reason the workspace failed to operate. If this field is empty, the workspace has not failed.
// This field is filled exclusively when caused by system errors.
string failed = 1;

// timeout contains the reason the workspace has timed out. If this field is empty, the workspace has not timed out.
string timeout = 2;

// first_user_activity is the time when MarkActive was first called on the workspace
google.protobuf.Timestamp first_user_activity = 9;

// stopped_by_request is true if the workspace was stopped using a StopWorkspace call
optional bool stopped_by_request = 11;
}

// Admission level describes who can access a workspace instance and its ports.
enum AdmissionLevel {
ADMISSION_LEVEL_UNSPECIFIED = 0;
Expand Down
Loading

0 comments on commit f8edb19

Please sign in to comment.