Skip to content

Commit eb5f701

Browse files
committed
conductor: "Adding mock service and resource for deploy-deliverypipeline"
1 parent da4be40 commit eb5f701

File tree

2 files changed

+772
-0
lines changed

2 files changed

+772
-0
lines changed
Lines changed: 299 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,299 @@
1+
google.cloud.deploy.v1.CloudDeploy
2+
in.proto.service.definition: service CloudDeploy {
3+
option (google.api.default_host) = "clouddeploy.googleapis.com";
4+
option (google.api.oauth_scopes) =
5+
"https://www.googleapis.com/auth/cloud-platform";
6+
7+
// Lists DeliveryPipelines in a given project and location.
8+
rpc ListDeliveryPipelines(ListDeliveryPipelinesRequest)
9+
returns (ListDeliveryPipelinesResponse) {
10+
option (google.api.http) = {
11+
get: "/v1/{parent=projects/*/locations/*}/deliveryPipelines"
12+
};
13+
option (google.api.method_signature) = "parent";
14+
}
15+
16+
// Gets details of a single DeliveryPipeline.
17+
rpc GetDeliveryPipeline(GetDeliveryPipelineRequest)
18+
returns (DeliveryPipeline) {
19+
option (google.api.http) = {
20+
get: "/v1/{name=projects/*/locations/*/deliveryPipelines/*}"
21+
};
22+
option (google.api.method_signature) = "name";
23+
}
24+
25+
// Creates a new DeliveryPipeline in a given project and location.
26+
rpc CreateDeliveryPipeline(CreateDeliveryPipelineRequest)
27+
returns (google.longrunning.Operation) {
28+
option (google.api.http) = {
29+
post: "/v1/{parent=projects/*/locations/*}/deliveryPipelines"
30+
body: "delivery_pipeline"
31+
};
32+
option (google.api.method_signature) =
33+
"parent,delivery_pipeline,delivery_pipeline_id";
34+
option (google.longrunning.operation_info) = {
35+
response_type: "DeliveryPipeline"
36+
metadata_type: "OperationMetadata"
37+
};
38+
}
39+
40+
// Updates the parameters of a single DeliveryPipeline.
41+
rpc UpdateDeliveryPipeline(UpdateDeliveryPipelineRequest)
42+
returns (google.longrunning.Operation) {
43+
option (google.api.http) = {
44+
patch: "/v1/{delivery_pipeline.name=projects/*/locations/*/deliveryPipelines/*}"
45+
body: "delivery_pipeline"
46+
};
47+
option (google.api.method_signature) = "delivery_pipeline,update_mask";
48+
option (google.longrunning.operation_info) = {
49+
response_type: "DeliveryPipeline"
50+
metadata_type: "OperationMetadata"
51+
};
52+
}
53+
54+
// Deletes a single DeliveryPipeline.
55+
rpc DeleteDeliveryPipeline(DeleteDeliveryPipelineRequest)
56+
returns (google.longrunning.Operation) {
57+
option (google.api.http) = {
58+
delete: "/v1/{name=projects/*/locations/*/deliveryPipelines/*}"
59+
};
60+
option (google.api.method_signature) = "name";
61+
option (google.longrunning.operation_info) = {
62+
response_type: "google.protobuf.Empty"
63+
metadata_type: "OperationMetadata"
64+
};
65+
}
66+
}
67+
out: // Copyright 2024 Google LLC
68+
//
69+
// Licensed under the Apache License, Version 2.0 (the "License");
70+
// you may not use this file except in compliance with the License.
71+
// You may obtain a copy of the License at
72+
//
73+
// http://www.apache.org/licenses/LICENSE-2.0
74+
//
75+
// Unless required by applicable law or agreed to in writing, software
76+
// distributed under the License is distributed on an "AS IS" BASIS,
77+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
78+
// See the License for the specific language governing permissions and
79+
// limitations under the License.
80+
81+
// +tool:mockgcp-support
82+
// proto.service: google.cloud.deploy.v1.CloudDeploy
83+
// proto.message: google.cloud.deploy.v1.DeliveryPipeline
84+
85+
package mockclouddeploy
86+
87+
import (
88+
"context"
89+
"fmt"
90+
"regexp"
91+
"strings"
92+
"time"
93+
94+
"google.golang.org/grpc/codes"
95+
"google.golang.org/grpc/status"
96+
"google.golang.org/protobuf/proto"
97+
"google.golang.org/protobuf/types/known/emptypb"
98+
"google.golang.org/protobuf/types/known/timestamppb"
99+
100+
"github.com/GoogleCloudPlatform/k8s-config-connector/mockgcp/common/projects"
101+
pb "github.com/GoogleCloudPlatform/k8s-config-connector/mockgcp/generated/mockgcp/cloud/deploy/v1"
102+
longrunningpb "google.golang.org/genproto/googleapis/longrunning"
103+
)
104+
105+
type cloudDeploy struct {
106+
*MockService
107+
pb.UnimplementedCloudDeployServer
108+
}
109+
110+
func (s *cloudDeploy) GetDeliveryPipeline(ctx context.Context, req *pb.GetDeliveryPipelineRequest) (*pb.DeliveryPipeline, error) {
111+
name, err := s.parseDeliveryPipelineName(req.Name)
112+
if err != nil {
113+
return nil, err
114+
}
115+
116+
fqn := name.String()
117+
118+
obj := &pb.DeliveryPipeline{}
119+
if err := s.storage.Get(ctx, fqn, obj); err != nil {
120+
if status.Code(err) == codes.NotFound {
121+
return nil, status.Errorf(codes.NotFound, "DeliveryPipeline %q not found", fqn)
122+
}
123+
return nil, err
124+
}
125+
126+
return obj, nil
127+
}
128+
129+
func (s *cloudDeploy) ListDeliveryPipelines(ctx context.Context, req *pb.ListDeliveryPipelinesRequest) (*pb.ListDeliveryPipelinesResponse, error) {
130+
response := &pb.ListDeliveryPipelinesResponse{}
131+
132+
parent, err := s.parseParentName(req.GetParent())
133+
if err != nil {
134+
return nil, err
135+
}
136+
137+
findPrefix := parent.String() + "/deliveryPipelines/"
138+
139+
deliveryPipelineKind := (&pb.DeliveryPipeline{}).ProtoReflect().Descriptor()
140+
if err := s.storage.List(ctx, deliveryPipelineKind, storage.ListOptions{}, func(obj proto.Message) error {
141+
deliveryPipeline := obj.(*pb.DeliveryPipeline)
142+
if strings.HasPrefix(deliveryPipeline.Name, findPrefix) {
143+
response.DeliveryPipelines = append(response.DeliveryPipelines, deliveryPipeline)
144+
}
145+
return nil
146+
}); err != nil {
147+
return nil, fmt.Errorf("error listing %v: %w", deliveryPipelineKind, err)
148+
}
149+
150+
return response, nil
151+
}
152+
153+
func (s *cloudDeploy) CreateDeliveryPipeline(ctx context.Context, req *pb.CreateDeliveryPipelineRequest) (*longrunningpb.Operation, error) {
154+
reqName := req.Parent + "/deliveryPipelines/" + req.DeliveryPipelineId
155+
name, err := s.parseDeliveryPipelineName(reqName)
156+
if err != nil {
157+
return nil, err
158+
}
159+
160+
fqn := name.String()
161+
162+
now := time.Now()
163+
164+
obj := proto.Clone(req.DeliveryPipeline).(*pb.DeliveryPipeline)
165+
obj.Name = fqn
166+
obj.Uid = "mock-uid-" + name.DeliveryPipelineID + "-" + name.Project.ID
167+
obj.CreateTime = timestamppb.New(now)
168+
obj.UpdateTime = timestamppb.New(now)
169+
obj.Condition = &pb.PipelineCondition{
170+
PipelineReadyCondition: &pb.PipelineReadyCondition{
171+
Status: true,
172+
LastUpdateTime: timestamppb.New(now),
173+
StatusMessage: "",
174+
StatusErrorCode: "",
175+
StatusErrorDetails: "",
176+
},
177+
}
178+
s.populateDefaultsForDeliveryPipeline(obj)
179+
180+
if err := s.storage.Create(ctx, fqn, obj); err != nil {
181+
return nil, err
182+
}
183+
184+
lroPrefix := fmt.Sprintf("projects/%s/locations/%s", name.Project.ID, name.Location)
185+
lroMetadata := &pb.OperationMetadata{
186+
ApiVersion: "v1",
187+
CreateTime: timestamppb.New(now),
188+
Target: name.String(),
189+
Verb: "create",
190+
}
191+
return s.operations.StartLRO(ctx, lroPrefix, lroMetadata, func() (proto.Message, error) {
192+
lroMetadata.EndTime = timestamppb.Now()
193+
194+
return obj, nil
195+
})
196+
}
197+
198+
func (s *cloudDeploy) populateDefaultsForDeliveryPipeline(obj *pb.DeliveryPipeline) {
199+
if obj.Etag == "" {
200+
obj.Etag = computeEtag(obj)
201+
}
202+
}
203+
204+
func (s *cloudDeploy) DeleteDeliveryPipeline(ctx context.Context, req *pb.DeleteDeliveryPipelineRequest) (*longrunningpb.Operation, error) {
205+
name, err := s.parseDeliveryPipelineName(req.Name)
206+
if err != nil {
207+
return nil, err
208+
}
209+
210+
fqn := name.String()
211+
212+
deleted := &pb.DeliveryPipeline{}
213+
if err := s.storage.Delete(ctx, fqn, deleted); err != nil {
214+
return nil, err
215+
}
216+
217+
lroPrefix := fmt.Sprintf("projects/%s/locations/%s", name.Project.ID, name.Location)
218+
lroMetadata := &pb.OperationMetadata{
219+
ApiVersion: "v1",
220+
CreateTime: timestamppb.New(time.Now()),
221+
Target: name.String(),
222+
Verb: "delete",
223+
}
224+
225+
return s.operations.StartLRO(ctx, lroPrefix, lroMetadata, func() (proto.Message, error) {
226+
lroMetadata.EndTime = timestamppb.New(time.Now())
227+
228+
return &emptypb.Empty{}, nil
229+
})
230+
}
231+
232+
type deliveryPipelineName struct {
233+
Project *projects.ProjectData
234+
Location string
235+
DeliveryPipelineID string
236+
}
237+
238+
func (n *deliveryPipelineName) String() string {
239+
return fmt.Sprintf("projects/%s/locations/%s/deliveryPipelines/%s", n.Project.ID, n.Location, n.DeliveryPipelineID)
240+
}
241+
242+
// parseDeliveryPipelineName parses a string into an deliveryPipelineName.
243+
// The expected form is `projects/*/locations/*/deliveryPipelines/*`.
244+
func (s *MockService) parseDeliveryPipelineName(name string) (*deliveryPipelineName, error) {
245+
tokens := strings.Split(name, "/")
246+
247+
if len(tokens) == 6 && tokens[0] == "projects" && tokens[2] == "locations" && tokens[4] == "deliveryPipelines" {
248+
project, err := s.Projects.GetProjectByID(tokens[1])
249+
if err != nil {
250+
return nil, err
251+
}
252+
253+
validID := regexp.MustCompile(`^[a-z]([a-z0-9-]{0,61}[a-z0-9])?$`).MatchString
254+
if !validID(tokens[5]) {
255+
return nil, status.Errorf(codes.InvalidArgument, "DeliveryPipeline id %q is not a valid name", name)
256+
}
257+
258+
name := &deliveryPipelineName{
259+
Project: project,
260+
Location: tokens[3],
261+
DeliveryPipelineID: tokens[5],
262+
}
263+
264+
return name, nil
265+
}
266+
267+
return nil, status.Errorf(codes.InvalidArgument, "name %q is not valid", name)
268+
}
269+
270+
type parentName struct {
271+
Project *projects.ProjectData
272+
Location string
273+
}
274+
275+
func (n *parentName) String() string {
276+
return fmt.Sprintf("projects/%s/locations/%s", n.Project.ID, n.Location)
277+
}
278+
279+
func (s *MockService) parseParentName(name string) (*parentName, error) {
280+
tokens := strings.Split(name, "/")
281+
282+
if len(tokens) == 4 && tokens[0] == "projects" && tokens[2] == "locations" {
283+
project, err := s.Projects.GetProjectByID(tokens[1])
284+
if err != nil {
285+
return nil, err
286+
}
287+
288+
name := &parentName{
289+
Project: project,
290+
Location: tokens[3],
291+
}
292+
293+
return name, nil
294+
}
295+
296+
return nil, status.Errorf(codes.InvalidArgument, "parent name %q is not valid", name)
297+
}
298+
299+

0 commit comments

Comments
 (0)