Skip to content

Commit 1cd7a6f

Browse files
authored
feat: create shared reservation (#4378)
1 parent 4eee984 commit 1cd7a6f

File tree

4 files changed

+165
-2
lines changed

4 files changed

+165
-2
lines changed

compute/go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ require (
77
cloud.google.com/go/storage v1.43.0
88
github.com/GoogleCloudPlatform/golang-samples v0.0.0-20240724083556-7f760db013b7
99
github.com/google/uuid v1.6.0
10+
github.com/googleapis/gax-go/v2 v2.13.0
1011
google.golang.org/api v0.193.0
1112
google.golang.org/protobuf v1.34.2
1213
)
@@ -23,7 +24,6 @@ require (
2324
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
2425
github.com/google/s2a-go v0.1.8 // indirect
2526
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
26-
github.com/googleapis/gax-go/v2 v2.13.0 // indirect
2727
go.opencensus.io v0.24.0 // indirect
2828
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.52.0 // indirect
2929
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// Copyright 2024 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package snippets
16+
17+
// [START compute_reservation_create_shared]
18+
import (
19+
"context"
20+
"fmt"
21+
"io"
22+
23+
computepb "cloud.google.com/go/compute/apiv1/computepb"
24+
"google.golang.org/protobuf/proto"
25+
)
26+
27+
// Creates shared reservation from given template in particular zone
28+
func createSharedReservation(w io.Writer, client ClientInterface, projectID, baseProjectId, zone, reservationName, sourceTemplate string) error {
29+
// client, err := compute.NewReservationsRESTClient(ctx)
30+
// projectID := "your_project_id". Destination of sharing.
31+
// baseProjectId := "your_project_id2". Project where the reservation will be created.
32+
// zone := "us-west3-a"
33+
// reservationName := "your_reservation_name"
34+
// sourceTemplate: existing template path. Following formats are allowed:
35+
// - projects/{project_id}/global/instanceTemplates/{template_name}
36+
// - projects/{project_id}/regions/{region}/instanceTemplates/{template_name}
37+
// - https://www.googleapis.com/compute/v1/projects/{project_id}/global/instanceTemplates/instanceTemplate
38+
// - https://www.googleapis.com/compute/v1/projects/{project_id}/regions/{region}/instanceTemplates/instanceTemplate
39+
40+
ctx := context.Background()
41+
42+
shareSettings := map[string]*computepb.ShareSettingsProjectConfig{
43+
projectID: {ProjectId: proto.String(projectID)},
44+
}
45+
46+
req := &computepb.InsertReservationRequest{
47+
Project: baseProjectId,
48+
ReservationResource: &computepb.Reservation{
49+
Name: proto.String(reservationName),
50+
Zone: proto.String(zone),
51+
SpecificReservation: &computepb.AllocationSpecificSKUReservation{
52+
Count: proto.Int64(2),
53+
SourceInstanceTemplate: proto.String(sourceTemplate),
54+
},
55+
ShareSettings: &computepb.ShareSettings{
56+
ProjectMap: shareSettings,
57+
ShareType: proto.String("SPECIFIC_PROJECTS"),
58+
},
59+
},
60+
Zone: zone,
61+
}
62+
63+
op, err := client.Insert(ctx, req)
64+
if err != nil {
65+
return fmt.Errorf("unable to create reservation: %w", err)
66+
}
67+
68+
if op != nil {
69+
if err = op.Wait(ctx); err != nil {
70+
return fmt.Errorf("unable to wait for the operation: %w", err)
71+
}
72+
}
73+
74+
fmt.Fprintf(w, "Reservation created\n")
75+
76+
return nil
77+
}
78+
79+
// [END compute_reservation_create_shared]
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Copyright 2024 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
// Mock objects for shared project
16+
17+
package snippets
18+
19+
import (
20+
"context"
21+
22+
compute "cloud.google.com/go/compute/apiv1"
23+
computepb "cloud.google.com/go/compute/apiv1/computepb"
24+
gax "github.com/googleapis/gax-go/v2"
25+
)
26+
27+
type ClientInterface interface {
28+
Close() error
29+
Delete(context.Context, *computepb.DeleteReservationRequest, ...gax.CallOption) (*compute.Operation, error)
30+
Insert(context.Context, *computepb.InsertReservationRequest, ...gax.CallOption) (*compute.Operation, error)
31+
}
32+
33+
type ReservationsClient struct{}
34+
35+
func (client ReservationsClient) Close() error {
36+
return nil
37+
}
38+
39+
func (client ReservationsClient) Insert(context.Context, *computepb.InsertReservationRequest, ...gax.CallOption) (*compute.Operation, error) {
40+
return nil, nil
41+
}
42+
43+
func (client ReservationsClient) Delete(context.Context, *computepb.DeleteReservationRequest, ...gax.CallOption) (*compute.Operation, error) {
44+
return nil, nil
45+
}

compute/reservations/reservations_test.go

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,6 @@ func TestReservations(t *testing.T) {
106106
templateName := fmt.Sprintf("test-template-%v-%v", time.Now().Format("01-02-2006"), r.Int())
107107

108108
var buf bytes.Buffer
109-
110109
err := createTemplate(tc.ProjectID, templateName)
111110
if err != nil {
112111
t.Errorf("createTemplate got err: %v", err)
@@ -200,4 +199,44 @@ func TestReservations(t *testing.T) {
200199
t.Errorf("deleteReservation got err: %v", err)
201200
}
202201
})
202+
203+
t.Run("Shared reservation CRUD", func(t *testing.T) {
204+
reservationName := fmt.Sprintf("test-reservation-%v-%v", time.Now().Format("01-02-2006"), r.Int())
205+
baseProjectID := tc.ProjectID
206+
// This test require 2 projects, therefore one of them is mocked.
207+
// If you want to make a real test, please adjust projectID accordingly and uncomment reservationsClient creation.
208+
// Make sure that base project has proper permissions to share reservations.
209+
// See: https://cloud.google.com/compute/docs/instances/reservations-shared#shared_reservation_constraint
210+
destinationProjectID := "some-project"
211+
ctx := context.Background()
212+
213+
want := "Reservation created"
214+
215+
// Uncomment line below if you want to run the test without mocks
216+
// reservationsClient, err := compute.NewReservationsRESTClient(ctx)
217+
reservationsClient := ReservationsClient{}
218+
if err != nil {
219+
t.Errorf("Couldn't create reservationsClient, err: %v", err)
220+
}
221+
defer reservationsClient.Close()
222+
223+
if err := createSharedReservation(&buf, reservationsClient, destinationProjectID, baseProjectID, zone, reservationName, *sourceTemplate.SelfLink); err != nil {
224+
t.Errorf("createSharedReservation got err: %v", err)
225+
}
226+
if got := buf.String(); !strings.Contains(got, want) {
227+
t.Errorf("createSharedReservation got %s, want %s", got, want)
228+
}
229+
buf.Reset()
230+
231+
req := &computepb.DeleteReservationRequest{
232+
Project: baseProjectID,
233+
Reservation: reservationName,
234+
Zone: zone,
235+
}
236+
237+
_, err = reservationsClient.Delete(ctx, req)
238+
if err != nil {
239+
t.Errorf("unable to delete reservation: %v", err)
240+
}
241+
})
203242
}

0 commit comments

Comments
 (0)