Skip to content

Commit

Permalink
mockGCP for compute firewall policy
Browse files Browse the repository at this point in the history
  • Loading branch information
gemmahou committed Oct 1, 2024
1 parent 3f7834e commit e2ce9af
Show file tree
Hide file tree
Showing 7 changed files with 318 additions and 2 deletions.
1 change: 1 addition & 0 deletions config/tests/samples/create/harness.go
Original file line number Diff line number Diff line change
Expand Up @@ -666,6 +666,7 @@ func MaybeSkip(t *testing.T, name string, resources []*unstructured.Unstructured
case schema.GroupKind{Group: "compute.cnrm.cloud.google.com", Kind: "ComputeAddress"}:
case schema.GroupKind{Group: "compute.cnrm.cloud.google.com", Kind: "ComputeBackendService"}:
case schema.GroupKind{Group: "compute.cnrm.cloud.google.com", Kind: "ComputeDisk"}:
case schema.GroupKind{Group: "compute.cnrm.cloud.google.com", Kind: "ComputeFirewallPolicy"}:
case schema.GroupKind{Group: "compute.cnrm.cloud.google.com", Kind: "ComputeForwardingRule"}:
case schema.GroupKind{Group: "compute.cnrm.cloud.google.com", Kind: "ComputeHealthCheck"}:
case schema.GroupKind{Group: "compute.cnrm.cloud.google.com", Kind: "ComputeInstance"}:
Expand Down
251 changes: 251 additions & 0 deletions mockgcp/mockcompute/firewallpoliciesv1.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package mockcompute

import (
"context"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/proto"
"strconv"
"strings"

pb "github.com/GoogleCloudPlatform/k8s-config-connector/mockgcp/generated/mockgcp/cloud/compute/v1"
)

type FirewallPoliciesV1 struct {
*MockService
pb.UnimplementedFirewallPoliciesServer
}

func (s *FirewallPoliciesV1) Get(ctx context.Context, req *pb.GetFirewallPolicyRequest) (*pb.FirewallPolicy, error) {
reqName := "locations/global/firewallPolicies/" + req.GetFirewallPolicy()
name, err := s.parseFirewallPolicyName(reqName)
if err != nil {
return nil, err
}

fqn := name.String()

obj := &pb.FirewallPolicy{}
if err := s.storage.Get(ctx, fqn, obj); err != nil {
if status.Code(err) == codes.NotFound {
return nil, status.Errorf(codes.NotFound, "The resource '%s' was not found", fqn)
}
return nil, err
}

return obj, nil
}

func (s *FirewallPoliciesV1) Insert(ctx context.Context, req *pb.InsertFirewallPolicyRequest) (*pb.Operation, error) {
policyId := req.GetFirewallPolicyResource().GetName()
id := s.generateID()
if policyId == "" {
policyId = strconv.FormatUint(id, 10)
}
reqName := "locations/global/firewallPolicies/" + policyId
policyName, err := s.parseFirewallPolicyName(reqName)
if err != nil {
return nil, err
}

fqn := policyName.String()

obj := proto.Clone(req.GetFirewallPolicyResource()).(*pb.FirewallPolicy)
obj.SelfLink = PtrTo("https://www.googleapis.com/compute/v1/" + policyName.String())
obj.SelfLinkWithId = PtrTo("https://www.googleapis.com/compute/v1/" + policyName.String() + "/" + policyId)
obj.Parent = PtrTo(req.ParentId)
obj.RuleTupleCount = PtrTo(int32(8))
obj.Id = PtrTo(id)
obj.Name = PtrTo(policyId)
obj.CreationTimestamp = PtrTo(s.nowString())
obj.Kind = PtrTo("compute#firewallPolicy")
obj.DisplayName = PtrTo(obj.GetShortName())

if obj.Fingerprint == nil {
obj.Fingerprint = PtrTo(computeFingerprint(obj))
}

// Use default rules
if obj.Rules == nil {
obj.Rules = []*pb.FirewallPolicyRule{
{
Action: PtrTo("goto_next"),
Description: PtrTo("default egress rule ipv6"),
Direction: PtrTo("EGRESS"),
EnableLogging: PtrTo(false),
Kind: PtrTo("compute#firewallPolicyRule"),
Match: &pb.FirewallPolicyRuleMatcher{
DestIpRanges: []string{"::/0"},
Layer4Configs: []*pb.FirewallPolicyRuleMatcherLayer4Config{
{
IpProtocol: PtrTo("all"),
},
},
},
Priority: PtrTo(int32(2147483644)),
RuleTupleCount: PtrTo(int32(2)),
},
{
Action: PtrTo("goto_next"),
Description: PtrTo("default ingress rule ipv6"),
Direction: PtrTo("INGRESS"),
EnableLogging: PtrTo(false),
Kind: PtrTo("compute#firewallPolicyRule"),
Match: &pb.FirewallPolicyRuleMatcher{
SrcIpRanges: []string{"::/0"},
Layer4Configs: []*pb.FirewallPolicyRuleMatcherLayer4Config{
{
IpProtocol: PtrTo("all"),
},
},
},
Priority: PtrTo(int32(2147483645)),
RuleTupleCount: PtrTo(int32(2)),
},
{
Action: PtrTo("goto_next"),
Description: PtrTo("default egress rule"),
Direction: PtrTo("EGRESS"),
EnableLogging: PtrTo(false),
Kind: PtrTo("compute#firewallPolicyRule"),
Match: &pb.FirewallPolicyRuleMatcher{
DestIpRanges: []string{"0.0.0.0/0"},
Layer4Configs: []*pb.FirewallPolicyRuleMatcherLayer4Config{
{
IpProtocol: PtrTo("all"),
},
},
},
Priority: PtrTo(int32(2147483646)),
RuleTupleCount: PtrTo(int32(2)),
},
{
Action: PtrTo("goto_next"),
Description: PtrTo("default ingress rule"),
Direction: PtrTo("INGRESS"),
EnableLogging: PtrTo(false),
Kind: PtrTo("compute#firewallPolicyRule"),
Match: &pb.FirewallPolicyRuleMatcher{
SrcIpRanges: []string{"0.0.0.0/0"},
Layer4Configs: []*pb.FirewallPolicyRuleMatcherLayer4Config{
{
IpProtocol: PtrTo("all"),
},
},
},
Priority: PtrTo(int32(2147483647)),
RuleTupleCount: PtrTo(int32(2)),
},
}
}

if err := s.storage.Create(ctx, fqn, obj); err != nil {
return nil, err
}

op := &pb.Operation{
TargetId: obj.Id,
TargetLink: obj.SelfLink,
OperationType: PtrTo("createFirewallPolicy"),
User: PtrTo("[email protected]"),
}
return s.startGlobalOrganizationLRO(ctx, op, func() (proto.Message, error) {
return obj, nil
})
}

func (s *FirewallPoliciesV1) Patch(ctx context.Context, req *pb.PatchFirewallPolicyRequest) (*pb.Operation, error) {
reqName := "locations/global/firewallPolicies/" + req.GetFirewallPolicy()

name, err := s.parseFirewallPolicyName(reqName)
if err != nil {
return nil, err
}

fqn := name.String()
obj := &pb.FirewallPolicy{}
if err := s.storage.Get(ctx, fqn, obj); err != nil {
return nil, err
}

proto.Merge(obj, req.GetFirewallPolicyResource())

if err := s.storage.Update(ctx, fqn, obj); err != nil {
return nil, err
}

op := &pb.Operation{
TargetId: obj.Id,
TargetLink: obj.SelfLink,
OperationType: PtrTo("updateFirewallPolicy"),
User: PtrTo("[email protected]"),
// patch operation finished super fast
Progress: PtrTo(int32(100)),
Status: PtrTo(pb.Operation_DONE),
EndTime: PtrTo("2024-04-01T12:34:56.123456Z"),
}
return s.startGlobalOrganizationLRO(ctx, op, func() (proto.Message, error) {
return obj, nil
})
}
func (s *FirewallPoliciesV1) Delete(ctx context.Context, req *pb.DeleteFirewallPolicyRequest) (*pb.Operation, error) {
reqName := "locations/global/firewallPolicies/" + req.GetFirewallPolicy()
name, err := s.parseFirewallPolicyName(reqName)
if err != nil {
return nil, err
}

fqn := name.String()

deleted := &pb.FirewallPolicy{}
if err := s.storage.Delete(ctx, fqn, deleted); err != nil {
return nil, err
}

op := &pb.Operation{
TargetId: deleted.Id,
TargetLink: deleted.SelfLink,
OperationType: PtrTo("deleteFirewallPolicy"),
User: PtrTo("[email protected]"),
}
return s.startGlobalOrganizationLRO(ctx, op, func() (proto.Message, error) {
return deleted, nil
})
}

type firewallPolicyName struct {
Name string
}

func (n *firewallPolicyName) String() string {
return "locations/global/firewallPolicies/" + n.Name
}

// parseFirewallPolicyName parses a string into a firewallPolicyName.
// The expected form is `locations/global/firewallPolicies/*`.
func (s *MockService) parseFirewallPolicyName(name string) (*firewallPolicyName, error) {
tokens := strings.Split(name, "/")

if len(tokens) == 4 && tokens[2] == "firewallPolicies" {
name := &firewallPolicyName{
Name: tokens[3],
}
return name, nil
} else {
return nil, status.Errorf(codes.InvalidArgument, "name %q is not valid", name)
}
}
36 changes: 36 additions & 0 deletions mockgcp/mockcompute/globalorganizationoperationsv1.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package mockcompute

import (
"context"

pb "github.com/GoogleCloudPlatform/k8s-config-connector/mockgcp/generated/mockgcp/cloud/compute/v1"
)

type GlobalOrganizationOperationsV1 struct {
*MockService
pb.UnimplementedGlobalOrganizationOperationsServer
}

func (s *GlobalOrganizationOperationsV1) Get(ctx context.Context, req *pb.GetGlobalOrganizationOperationRequest) (*pb.Operation, error) {
fqn := s.globalOrganizationOperationFQN(req.Operation)
lro, err := s.getOperation(ctx, fqn)
if err != nil {
return nil, err
}

return lro, nil
}
16 changes: 16 additions & 0 deletions mockgcp/mockcompute/operations.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ func (s *computeOperations) globalOperationFQN(projectID string, name string) st
return "projects/" + projectID + "/global/operations/" + name
}

func (s *computeOperations) globalOrganizationOperationFQN(name string) string {
return "locations/global/operations/" + name
}

func (s *computeOperations) regionalOperationFQN(projectID string, region string, name string) string {
return "projects/" + projectID + "/regions/" + region + "/operations/" + name
}
Expand Down Expand Up @@ -158,6 +162,18 @@ func (s *computeOperations) startGlobalLRO(ctx context.Context, projectID string
return s.startLRO0(ctx, op, fqn, callback)
}

func (s *computeOperations) startGlobalOrganizationLRO(ctx context.Context, op *pb.Operation, callback func() (proto.Message, error)) (*pb.Operation, error) {
now := time.Now()
millis := now.UnixMilli()
id := uuid.NewUUID()

name := fmt.Sprintf("operation-%d-%s", millis, id)
fqn := s.globalOrganizationOperationFQN(name)

op.Name = PtrTo(name)
return s.startLRO0(ctx, op, fqn, callback)
}

// Gets the latest state of a long-running operation. Clients can use this
// method to poll the operation result at intervals as recommended by the API
// service.
Expand Down
10 changes: 10 additions & 0 deletions mockgcp/mockcompute/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ func (s *MockService) Register(grpcServer *grpc.Server) {

pb.RegisterRegionOperationsServer(grpcServer, &RegionalOperationsV1{MockService: s})
pb.RegisterGlobalOperationsServer(grpcServer, &GlobalOperationsV1{MockService: s})
pb.RegisterGlobalOrganizationOperationsServer(grpcServer, &GlobalOrganizationOperationsV1{MockService: s})

pb.RegisterNodeGroupsServer(grpcServer, &NodeGroupsV1{MockService: s})
pb.RegisterNodeTemplatesServer(grpcServer, &NodeTemplatesV1{MockService: s})
Expand All @@ -89,6 +90,8 @@ func (s *MockService) Register(grpcServer *grpc.Server) {

pb.RegisterServiceAttachmentsServer(grpcServer, &RegionalServiceAttachmentV1{MockService: s})

pb.RegisterFirewallPoliciesServer(grpcServer, &FirewallPoliciesV1{MockService: s})

pb.RegisterGlobalForwardingRulesServer(grpcServer, &GlobalForwardingRulesV1{MockService: s})
pb.RegisterForwardingRulesServer(grpcServer, &RegionalForwardingRulesV1{MockService: s})

Expand Down Expand Up @@ -170,6 +173,10 @@ func (s *MockService) NewHTTPMux(ctx context.Context, conn *grpc.ClientConn) (ht
return nil, err
}

if err := pb.RegisterFirewallPoliciesHandler(ctx, mux.ServeMux, conn); err != nil {
return nil, err
}

if err := pb.RegisterForwardingRulesHandler(ctx, mux.ServeMux, conn); err != nil {
return nil, err
}
Expand All @@ -183,6 +190,9 @@ func (s *MockService) NewHTTPMux(ctx context.Context, conn *grpc.ClientConn) (ht
if err := pb.RegisterGlobalOperationsHandler(ctx, mux.ServeMux, conn); err != nil {
return nil, err
}
if err := pb.RegisterGlobalOrganizationOperationsHandler(ctx, mux.ServeMux, conn); err != nil {
return nil, err
}

if err := pb.RegisterAddressesHandler(ctx, mux.ServeMux, conn); err != nil {
return nil, err
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,5 @@ status:
id: 1111111111111111
observedGeneration: 3
ruleTupleCount: 8
selfLink: https://www.googleapis.com/compute/beta/locations/global/firewallPolicies/${firewallPolicyID}
selfLinkWithId: https://www.googleapis.com/compute/beta/locations/global/firewallPolicies/${firewallPolicyID}/${firewallPolicyID}
selfLink: https://www.googleapis.com/compute/v1/locations/global/firewallPolicies/${firewallPolicyID}
selfLinkWithId: https://www.googleapis.com/compute/v1/locations/global/firewallPolicies/${firewallPolicyID}/${firewallPolicyID}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ X-Xss-Protection: 0
"selfLink": "https://www.googleapis.com/compute/v1/locations/global/operations/${operationID}",
"startTime": "2024-04-01T12:34:56.123456Z",
"status": "RUNNING",
"targetId": "${firewallPolicyId}",
"targetLink": "https://www.googleapis.com/compute/v1/locations/global/firewallPolicies/${firewallPolicyId}",
"user": "[email protected]"
}

Expand Down

0 comments on commit e2ce9af

Please sign in to comment.