Skip to content

Commit 9a137be

Browse files
committed
feat(api): enhance environment management with create, start, stop, and delete options
1 parent 0625956 commit 9a137be

File tree

1 file changed

+146
-39
lines changed

1 file changed

+146
-39
lines changed

lib/sandbox/sandbox.go

Lines changed: 146 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ import (
44
"context"
55
"errors"
66
"fmt"
7-
"time"
7+
"net/http"
88

99
"github.com/stainless-sdks/gitpod-go"
10+
"github.com/stainless-sdks/gitpod-go/internal/apierror"
1011
)
1112

1213
type EnvironmentSandbox struct {
@@ -19,84 +20,190 @@ func NewEnvironmentSandbox(client *gitpod.Client) *EnvironmentSandbox {
1920
}
2021
}
2122

22-
type CreateEnvironmentParams struct {
23+
type CreateEnvironmentOptions struct {
2324
ProjectID string
2425
ContextURL string
2526
EnvironmentClass string
2627
}
2728

28-
func (s *EnvironmentSandbox) Create(ctx context.Context, params *CreateEnvironmentParams) (res *gitpod.EnvironmentGetResponseEnvironment, err error) {
29-
envID, err := s.create(ctx, params)
29+
func (s *EnvironmentSandbox) Create(ctx context.Context, options *CreateEnvironmentOptions) (res *gitpod.EnvironmentGetResponseEnvironment, err error) {
30+
envID, err := s.create(ctx, options)
3031
if err != nil {
3132
return nil, err
3233
}
3334
return s.waitForRunning(ctx, envID)
3435
}
3536

37+
type StartEnvironmentOptions struct {
38+
EnvironmentID string
39+
}
40+
41+
func (s *EnvironmentSandbox) Start(ctx context.Context, options *StartEnvironmentOptions) (res *gitpod.EnvironmentGetResponseEnvironment, err error) {
42+
_, err = s.Client.Environments.Start(ctx, gitpod.EnvironmentStartParams{
43+
EnvironmentID: gitpod.String(options.EnvironmentID),
44+
})
45+
if err != nil {
46+
return nil, err
47+
}
48+
return s.waitForRunning(ctx, options.EnvironmentID)
49+
}
50+
51+
type StopEnvironmentOptions struct {
52+
EnvironmentID string
53+
}
54+
55+
func (s *EnvironmentSandbox) Stop(ctx context.Context, options *StopEnvironmentOptions) (res *gitpod.EnvironmentGetResponseEnvironment, err error) {
56+
_, err = s.Client.Environments.Stop(ctx, gitpod.EnvironmentStopParams{
57+
EnvironmentID: gitpod.String(options.EnvironmentID),
58+
})
59+
if err != nil {
60+
return nil, err
61+
}
62+
return s.waitForStopped(ctx, options.EnvironmentID)
63+
}
64+
65+
type DeleteEnvironmentOptions struct {
66+
EnvironmentID string
67+
}
68+
69+
func (s *EnvironmentSandbox) Delete(ctx context.Context, options *DeleteEnvironmentOptions) error {
70+
_, err := s.Client.Environments.Delete(ctx, gitpod.EnvironmentDeleteParams{
71+
EnvironmentID: gitpod.String(options.EnvironmentID),
72+
})
73+
if err != nil {
74+
apierr, ok := err.(*apierror.Error)
75+
if ok && apierr.StatusCode == http.StatusNotFound {
76+
return nil
77+
}
78+
return err
79+
}
80+
return s.waitForDeleted(ctx, options.EnvironmentID)
81+
}
82+
83+
func (s *EnvironmentSandbox) waitForDeleted(ctx context.Context, envID string) error {
84+
_, err := s.waitFor(ctx, envID, func() (*gitpod.EnvironmentGetResponseEnvironment, bool, error) {
85+
resp, err := s.Client.Environments.Get(ctx, gitpod.EnvironmentGetParams{
86+
EnvironmentID: gitpod.String(envID),
87+
})
88+
if err != nil {
89+
apierr, ok := err.(*apierror.Error)
90+
if ok && apierr.StatusCode == http.StatusNotFound {
91+
return nil, true, nil
92+
}
93+
return nil, false, err
94+
}
95+
return nil, resp.Environment.Status.Phase == gitpod.EnvironmentGetResponseEnvironmentStatusPhaseEnvironmentPhaseDeleted, nil
96+
})
97+
return err
98+
}
99+
100+
func (s *EnvironmentSandbox) waitForStopped(ctx context.Context, envID string) (*gitpod.EnvironmentGetResponseEnvironment, error) {
101+
return s.waitFor(ctx, envID, func() (*gitpod.EnvironmentGetResponseEnvironment, bool, error) {
102+
resp, err := s.Client.Environments.Get(ctx, gitpod.EnvironmentGetParams{
103+
EnvironmentID: gitpod.String(envID),
104+
})
105+
if err != nil {
106+
return nil, false, err
107+
}
108+
if resp.Environment.Status.Phase == gitpod.EnvironmentGetResponseEnvironmentStatusPhaseEnvironmentPhaseStopped ||
109+
resp.Environment.Status.Phase == gitpod.EnvironmentGetResponseEnvironmentStatusPhaseEnvironmentPhaseDeleting ||
110+
resp.Environment.Status.Phase == gitpod.EnvironmentGetResponseEnvironmentStatusPhaseEnvironmentPhaseDeleted {
111+
return &resp.Environment, true, nil
112+
}
113+
return nil, false, nil
114+
})
115+
}
116+
36117
func (s *EnvironmentSandbox) waitForRunning(ctx context.Context, envID string) (*gitpod.EnvironmentGetResponseEnvironment, error) {
37-
tick := time.NewTicker(500 * time.Microsecond)
38-
defer tick.Stop()
39-
for {
40-
select {
41-
case <-ctx.Done():
42-
return nil, ctx.Err()
43-
case <-tick.C:
44-
resp, err := s.Client.Environments.Get(ctx, gitpod.EnvironmentGetParams{
45-
EnvironmentID: gitpod.String(envID),
46-
})
118+
return s.waitFor(ctx, envID, func() (*gitpod.EnvironmentGetResponseEnvironment, bool, error) {
119+
resp, err := s.Client.Environments.Get(ctx, gitpod.EnvironmentGetParams{
120+
EnvironmentID: gitpod.String(envID),
121+
})
122+
if err != nil {
123+
return nil, false, err
124+
}
125+
126+
if fm := resp.Environment.Status.FailureMessage; len(fm) > 0 {
127+
return nil, false, fmt.Errorf("environment creation failed: %s", fm)
128+
}
129+
if resp.Environment.Status.Phase == gitpod.EnvironmentGetResponseEnvironmentStatusPhaseEnvironmentPhaseRunning {
130+
return &resp.Environment, true, nil
131+
}
132+
if resp.Environment.Status.Phase == gitpod.EnvironmentGetResponseEnvironmentStatusPhaseEnvironmentPhaseStopping {
133+
return nil, false, errors.New("environment creation failed: environment is stopping")
134+
}
135+
if resp.Environment.Status.Phase == gitpod.EnvironmentGetResponseEnvironmentStatusPhaseEnvironmentPhaseStopped {
136+
return nil, false, errors.New("environment creation failed: environment is stopped")
137+
}
138+
if resp.Environment.Status.Phase == gitpod.EnvironmentGetResponseEnvironmentStatusPhaseEnvironmentPhaseDeleting {
139+
return nil, false, errors.New("environment creation failed: environment is deleting")
140+
}
141+
if resp.Environment.Status.Phase == gitpod.EnvironmentGetResponseEnvironmentStatusPhaseEnvironmentPhaseDeleted {
142+
return nil, false, errors.New("environment creation failed: environment is deleted")
143+
}
144+
return nil, false, nil
145+
})
146+
}
147+
148+
func (s *EnvironmentSandbox) waitFor(ctx context.Context, envID string, fetch func() (*gitpod.EnvironmentGetResponseEnvironment, bool, error)) (*gitpod.EnvironmentGetResponseEnvironment, error) {
149+
env, ok, err := fetch()
150+
if err != nil {
151+
return nil, err
152+
}
153+
if ok {
154+
return env, nil
155+
}
156+
157+
stream := s.Client.Events.WatchStreaming(ctx, gitpod.EventWatchParams{
158+
Body: gitpod.EventWatchParamsBodyEnvironmentScopeProducesEventsForTheEnvironmentItselfAllTasksTaskExecutionsAndServicesAssociatedWithThatEnvironment{
159+
EnvironmentID: gitpod.String(envID),
160+
},
161+
})
162+
defer stream.Close()
163+
164+
for stream.Next() {
165+
resp := stream.Current()
166+
if resp.ResourceType == gitpod.EventWatchResponseResourceTypeResourceTypeEnvironment && resp.ResourceID == envID {
167+
env, ok, err := fetch()
47168
if err != nil {
48169
// TODO: if transient we should retry?
49170
return nil, err
50171
}
51-
52-
if fm := resp.Environment.Status.FailureMessage; len(fm) > 0 {
53-
return nil, fmt.Errorf("environment creation failed: %s", fm)
54-
}
55-
if resp.Environment.Status.Phase == gitpod.EnvironmentGetResponseEnvironmentStatusPhaseEnvironmentPhaseRunning {
56-
return &resp.Environment, nil
57-
}
58-
if resp.Environment.Status.Phase == gitpod.EnvironmentGetResponseEnvironmentStatusPhaseEnvironmentPhaseStopping {
59-
return nil, errors.New("environment creation failed: environment is stopping")
60-
}
61-
if resp.Environment.Status.Phase == gitpod.EnvironmentGetResponseEnvironmentStatusPhaseEnvironmentPhaseStopped {
62-
return nil, errors.New("environment creation failed: environment is stopped")
63-
}
64-
if resp.Environment.Status.Phase == gitpod.EnvironmentGetResponseEnvironmentStatusPhaseEnvironmentPhaseDeleting {
65-
return nil, errors.New("environment creation failed: environment is deleting")
66-
}
67-
if resp.Environment.Status.Phase == gitpod.EnvironmentGetResponseEnvironmentStatusPhaseEnvironmentPhaseDeleted {
68-
return nil, errors.New("environment creation failed: environment is deleted")
172+
if ok {
173+
return env, nil
69174
}
70175
}
71176
}
177+
178+
return nil, stream.Err()
72179
}
73180

74-
func (s *EnvironmentSandbox) create(ctx context.Context, params *CreateEnvironmentParams) (string, error) {
75-
if params.ProjectID != "" {
181+
func (s *EnvironmentSandbox) create(ctx context.Context, options *CreateEnvironmentOptions) (string, error) {
182+
if options.ProjectID != "" {
76183
resp, err := s.Client.Environments.NewFromProject(ctx, gitpod.EnvironmentNewFromProjectParams{
77-
ProjectID: gitpod.String(params.ProjectID),
184+
ProjectID: gitpod.String(options.ProjectID),
78185
})
79186
if err != nil {
80187
return "", err
81188
}
82189
return resp.Environment.ID, nil
83190
}
84-
if params.ContextURL != "" {
85-
if params.EnvironmentClass == "" {
191+
if options.ContextURL != "" {
192+
if options.EnvironmentClass == "" {
86193
return "", errors.New("environmentClass must be provided when contextURL is provided")
87194
}
88195
resp, err := s.Client.Environments.New(ctx, gitpod.EnvironmentNewParams{
89196
Spec: gitpod.F(gitpod.EnvironmentNewParamsSpec{
90197
DesiredPhase: gitpod.F(gitpod.EnvironmentNewParamsSpecDesiredPhaseEnvironmentPhaseRunning),
91198
Machine: gitpod.F(gitpod.EnvironmentNewParamsSpecMachine{
92-
Class: gitpod.String(params.EnvironmentClass),
199+
Class: gitpod.String(options.EnvironmentClass),
93200
}),
94201
Content: gitpod.F(gitpod.EnvironmentNewParamsSpecContent{
95202
Initializer: gitpod.F(gitpod.EnvironmentNewParamsSpecContentInitializer{
96203
Specs: gitpod.F([]gitpod.EnvironmentNewParamsSpecContentInitializerSpecUnion{
97204
gitpod.EnvironmentNewParamsSpecContentInitializerSpecsContextURL{
98205
ContextURL: gitpod.F(gitpod.EnvironmentNewParamsSpecContentInitializerSpecsContextURLContextURL{
99-
URL: gitpod.String(params.ContextURL),
206+
URL: gitpod.String(options.ContextURL),
100207
}),
101208
},
102209
}),

0 commit comments

Comments
 (0)