diff --git a/python/proto/eventarc/BUILD b/python/proto/eventarc/BUILD index 6c76214be..fe6152564 100755 --- a/python/proto/eventarc/BUILD +++ b/python/proto/eventarc/BUILD @@ -13,4 +13,4 @@ # limitations under the License. load("//:connector_rules.bzl", "proto_package") -proto_package(name="eventarc", resources=["trigger"]) +proto_package(name="eventarc", resources=["trigger","channel"]) diff --git a/python/proto/eventarc/alpha/BUILD b/python/proto/eventarc/alpha/BUILD index 802ea4a60..0d30008fe 100755 --- a/python/proto/eventarc/alpha/BUILD +++ b/python/proto/eventarc/alpha/BUILD @@ -13,4 +13,4 @@ # limitations under the License. load("//:connector_rules.bzl", "proto_package") -proto_package(name="eventarc/alpha", resources=["trigger"]) +proto_package(name="eventarc/alpha", resources=["trigger","channel"]) diff --git a/python/proto/eventarc/alpha/channel.proto b/python/proto/eventarc/alpha/channel.proto new file mode 100755 index 000000000..97aee4397 --- /dev/null +++ b/python/proto/eventarc/alpha/channel.proto @@ -0,0 +1,71 @@ +// Copyright 2022 Google LLC. All Rights Reserved. +// +// 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. +syntax = "proto3"; +// All generated protos should be opaque, with "xxx_hidden_" prepended to their field names. + + +package dcl; + +import "proto/connector/sdk.proto"; +import "proto/empty.proto"; + + +enum EventarcAlphaChannelStateEnum { + EventarcAlphaChannelStateEnumNO_VALUE_DO_NOT_USE = 0; + EventarcAlphaChannelStateEnumSTATE_UNSPECIFIED = 1; + EventarcAlphaChannelStateEnumPENDING = 2; + EventarcAlphaChannelStateEnumACTIVE = 3; + EventarcAlphaChannelStateEnumINACTIVE = 4; +} + +message EventarcAlphaChannel { + string name = 1; + string uid = 2; + string create_time = 3; + string update_time = 4; + string provider = 5; + string pubsub_topic = 6; + EventarcAlphaChannelStateEnum state = 7; + string activation_token = 8; + string crypto_key_name = 9; + string project = 10; + string location = 11; +} + +message ApplyEventarcAlphaChannelRequest { + EventarcAlphaChannel resource = 1; + repeated LifecycleDirective lifecycle_directives = 2; + string service_account_file = 3; +} + +message DeleteEventarcAlphaChannelRequest { + string service_account_file = 1; + EventarcAlphaChannel resource = 2; +} + +message ListEventarcAlphaChannelRequest { + string service_account_file = 1; + string Project = 2; + string Location = 3; +} + +message ListEventarcAlphaChannelResponse { + repeated EventarcAlphaChannel items = 1; +} + +service EventarcAlphaChannelService { + rpc ApplyEventarcAlphaChannel(ApplyEventarcAlphaChannelRequest) returns (EventarcAlphaChannel); + rpc DeleteEventarcAlphaChannel(DeleteEventarcAlphaChannelRequest) returns (google.protobuf.Empty); + rpc ListEventarcAlphaChannel(ListEventarcAlphaChannelRequest) returns (ListEventarcAlphaChannelResponse); +} diff --git a/python/proto/eventarc/beta/BUILD b/python/proto/eventarc/beta/BUILD index 8a21b49c6..65a3993dc 100755 --- a/python/proto/eventarc/beta/BUILD +++ b/python/proto/eventarc/beta/BUILD @@ -13,4 +13,4 @@ # limitations under the License. load("//:connector_rules.bzl", "proto_package") -proto_package(name="eventarc/beta", resources=["trigger"]) +proto_package(name="eventarc/beta", resources=["trigger","channel"]) diff --git a/python/proto/eventarc/beta/channel.proto b/python/proto/eventarc/beta/channel.proto new file mode 100755 index 000000000..dba876bf9 --- /dev/null +++ b/python/proto/eventarc/beta/channel.proto @@ -0,0 +1,71 @@ +// Copyright 2022 Google LLC. All Rights Reserved. +// +// 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. +syntax = "proto3"; +// All generated protos should be opaque, with "xxx_hidden_" prepended to their field names. + + +package dcl; + +import "proto/connector/sdk.proto"; +import "proto/empty.proto"; + + +enum EventarcBetaChannelStateEnum { + EventarcBetaChannelStateEnumNO_VALUE_DO_NOT_USE = 0; + EventarcBetaChannelStateEnumSTATE_UNSPECIFIED = 1; + EventarcBetaChannelStateEnumPENDING = 2; + EventarcBetaChannelStateEnumACTIVE = 3; + EventarcBetaChannelStateEnumINACTIVE = 4; +} + +message EventarcBetaChannel { + string name = 1; + string uid = 2; + string create_time = 3; + string update_time = 4; + string provider = 5; + string pubsub_topic = 6; + EventarcBetaChannelStateEnum state = 7; + string activation_token = 8; + string crypto_key_name = 9; + string project = 10; + string location = 11; +} + +message ApplyEventarcBetaChannelRequest { + EventarcBetaChannel resource = 1; + repeated LifecycleDirective lifecycle_directives = 2; + string service_account_file = 3; +} + +message DeleteEventarcBetaChannelRequest { + string service_account_file = 1; + EventarcBetaChannel resource = 2; +} + +message ListEventarcBetaChannelRequest { + string service_account_file = 1; + string Project = 2; + string Location = 3; +} + +message ListEventarcBetaChannelResponse { + repeated EventarcBetaChannel items = 1; +} + +service EventarcBetaChannelService { + rpc ApplyEventarcBetaChannel(ApplyEventarcBetaChannelRequest) returns (EventarcBetaChannel); + rpc DeleteEventarcBetaChannel(DeleteEventarcBetaChannelRequest) returns (google.protobuf.Empty); + rpc ListEventarcBetaChannel(ListEventarcBetaChannelRequest) returns (ListEventarcBetaChannelResponse); +} diff --git a/python/proto/eventarc/channel.proto b/python/proto/eventarc/channel.proto new file mode 100755 index 000000000..6bcb5c096 --- /dev/null +++ b/python/proto/eventarc/channel.proto @@ -0,0 +1,71 @@ +// Copyright 2022 Google LLC. All Rights Reserved. +// +// 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. +syntax = "proto3"; +// All generated protos should be opaque, with "xxx_hidden_" prepended to their field names. + + +package dcl; + +import "proto/connector/sdk.proto"; +import "proto/empty.proto"; + + +enum EventarcChannelStateEnum { + EventarcChannelStateEnumNO_VALUE_DO_NOT_USE = 0; + EventarcChannelStateEnumSTATE_UNSPECIFIED = 1; + EventarcChannelStateEnumPENDING = 2; + EventarcChannelStateEnumACTIVE = 3; + EventarcChannelStateEnumINACTIVE = 4; +} + +message EventarcChannel { + string name = 1; + string uid = 2; + string create_time = 3; + string update_time = 4; + string provider = 5; + string pubsub_topic = 6; + EventarcChannelStateEnum state = 7; + string activation_token = 8; + string crypto_key_name = 9; + string project = 10; + string location = 11; +} + +message ApplyEventarcChannelRequest { + EventarcChannel resource = 1; + repeated LifecycleDirective lifecycle_directives = 2; + string service_account_file = 3; +} + +message DeleteEventarcChannelRequest { + string service_account_file = 1; + EventarcChannel resource = 2; +} + +message ListEventarcChannelRequest { + string service_account_file = 1; + string Project = 2; + string Location = 3; +} + +message ListEventarcChannelResponse { + repeated EventarcChannel items = 1; +} + +service EventarcChannelService { + rpc ApplyEventarcChannel(ApplyEventarcChannelRequest) returns (EventarcChannel); + rpc DeleteEventarcChannel(DeleteEventarcChannelRequest) returns (google.protobuf.Empty); + rpc ListEventarcChannel(ListEventarcChannelRequest) returns (ListEventarcChannelResponse); +} diff --git a/python/services/eventarc/BUILD b/python/services/eventarc/BUILD index cd1f79e6f..30b34b8f9 100755 --- a/python/services/eventarc/BUILD +++ b/python/services/eventarc/BUILD @@ -13,4 +13,4 @@ # limitations under the License. load("//:connector_rules.bzl", "connector") -connector(name="eventarc", resources=["trigger"]) +connector(name="eventarc", resources=["trigger","channel"]) diff --git a/python/services/eventarc/alpha/BUILD b/python/services/eventarc/alpha/BUILD index b47afa183..53e650820 100755 --- a/python/services/eventarc/alpha/BUILD +++ b/python/services/eventarc/alpha/BUILD @@ -13,4 +13,4 @@ # limitations under the License. load("//:connector_rules.bzl", "connector") -connector(name="eventarc/alpha", resources=["trigger"]) +connector(name="eventarc/alpha", resources=["trigger","channel"]) diff --git a/python/services/eventarc/alpha/channel.py b/python/services/eventarc/alpha/channel.py new file mode 100755 index 000000000..9451b6e06 --- /dev/null +++ b/python/services/eventarc/alpha/channel.py @@ -0,0 +1,153 @@ +# Copyright 2022 Google LLC. All Rights Reserved. +# +# 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. +from connector import channel +from google3.cloud.graphite.mmv2.services.google.eventarc import channel_pb2 +from google3.cloud.graphite.mmv2.services.google.eventarc import channel_pb2_grpc + +from typing import List + + +class Channel(object): + def __init__( + self, + name: str = None, + uid: str = None, + create_time: str = None, + update_time: str = None, + provider: str = None, + pubsub_topic: str = None, + state: str = None, + activation_token: str = None, + crypto_key_name: str = None, + project: str = None, + location: str = None, + service_account_file: str = "", + ): + + channel.initialize() + self.name = name + self.provider = provider + self.crypto_key_name = crypto_key_name + self.project = project + self.location = location + self.service_account_file = service_account_file + + def apply(self): + stub = channel_pb2_grpc.EventarcAlphaChannelServiceStub(channel.Channel()) + request = channel_pb2.ApplyEventarcAlphaChannelRequest() + if Primitive.to_proto(self.name): + request.resource.name = Primitive.to_proto(self.name) + + if Primitive.to_proto(self.provider): + request.resource.provider = Primitive.to_proto(self.provider) + + if Primitive.to_proto(self.crypto_key_name): + request.resource.crypto_key_name = Primitive.to_proto(self.crypto_key_name) + + if Primitive.to_proto(self.project): + request.resource.project = Primitive.to_proto(self.project) + + if Primitive.to_proto(self.location): + request.resource.location = Primitive.to_proto(self.location) + + request.service_account_file = self.service_account_file + + response = stub.ApplyEventarcAlphaChannel(request) + self.name = Primitive.from_proto(response.name) + self.uid = Primitive.from_proto(response.uid) + self.create_time = Primitive.from_proto(response.create_time) + self.update_time = Primitive.from_proto(response.update_time) + self.provider = Primitive.from_proto(response.provider) + self.pubsub_topic = Primitive.from_proto(response.pubsub_topic) + self.state = ChannelStateEnum.from_proto(response.state) + self.activation_token = Primitive.from_proto(response.activation_token) + self.crypto_key_name = Primitive.from_proto(response.crypto_key_name) + self.project = Primitive.from_proto(response.project) + self.location = Primitive.from_proto(response.location) + + def delete(self): + stub = channel_pb2_grpc.EventarcAlphaChannelServiceStub(channel.Channel()) + request = channel_pb2.DeleteEventarcAlphaChannelRequest() + request.service_account_file = self.service_account_file + if Primitive.to_proto(self.name): + request.resource.name = Primitive.to_proto(self.name) + + if Primitive.to_proto(self.provider): + request.resource.provider = Primitive.to_proto(self.provider) + + if Primitive.to_proto(self.crypto_key_name): + request.resource.crypto_key_name = Primitive.to_proto(self.crypto_key_name) + + if Primitive.to_proto(self.project): + request.resource.project = Primitive.to_proto(self.project) + + if Primitive.to_proto(self.location): + request.resource.location = Primitive.to_proto(self.location) + + response = stub.DeleteEventarcAlphaChannel(request) + + @classmethod + def list(self, project, location, service_account_file=""): + stub = channel_pb2_grpc.EventarcAlphaChannelServiceStub(channel.Channel()) + request = channel_pb2.ListEventarcAlphaChannelRequest() + request.service_account_file = service_account_file + request.Project = project + + request.Location = location + + return stub.ListEventarcAlphaChannel(request).items + + def to_proto(self): + resource = channel_pb2.EventarcAlphaChannel() + if Primitive.to_proto(self.name): + resource.name = Primitive.to_proto(self.name) + if Primitive.to_proto(self.provider): + resource.provider = Primitive.to_proto(self.provider) + if Primitive.to_proto(self.crypto_key_name): + resource.crypto_key_name = Primitive.to_proto(self.crypto_key_name) + if Primitive.to_proto(self.project): + resource.project = Primitive.to_proto(self.project) + if Primitive.to_proto(self.location): + resource.location = Primitive.to_proto(self.location) + return resource + + +class ChannelStateEnum(object): + @classmethod + def to_proto(self, resource): + if not resource: + return resource + return channel_pb2.EventarcAlphaChannelStateEnum.Value( + "EventarcAlphaChannelStateEnum%s" % resource + ) + + @classmethod + def from_proto(self, resource): + if not resource: + return resource + return channel_pb2.EventarcAlphaChannelStateEnum.Name(resource)[ + len("EventarcAlphaChannelStateEnum") : + ] + + +class Primitive(object): + @classmethod + def to_proto(self, s): + if not s: + return "" + return s + + @classmethod + def from_proto(self, s): + return s diff --git a/python/services/eventarc/alpha/channel_server.go b/python/services/eventarc/alpha/channel_server.go new file mode 100755 index 000000000..447e6f3b2 --- /dev/null +++ b/python/services/eventarc/alpha/channel_server.go @@ -0,0 +1,142 @@ +// Copyright 2022 Google LLC. All Rights Reserved. +// +// 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 server + +import ( + "context" + "github.com/GoogleCloudPlatform/declarative-resource-client-library/dcl" + emptypb "github.com/GoogleCloudPlatform/declarative-resource-client-library/python/proto/empty_go_proto" + alphapb "github.com/GoogleCloudPlatform/declarative-resource-client-library/python/proto/eventarc/alpha/eventarc_alpha_go_proto" + "github.com/GoogleCloudPlatform/declarative-resource-client-library/services/google/eventarc/alpha" +) + +// ChannelServer implements the gRPC interface for Channel. +type ChannelServer struct{} + +// ProtoToChannelStateEnum converts a ChannelStateEnum enum from its proto representation. +func ProtoToEventarcAlphaChannelStateEnum(e alphapb.EventarcAlphaChannelStateEnum) *alpha.ChannelStateEnum { + if e == 0 { + return nil + } + if n, ok := alphapb.EventarcAlphaChannelStateEnum_name[int32(e)]; ok { + e := alpha.ChannelStateEnum(n[len("EventarcAlphaChannelStateEnum"):]) + return &e + } + return nil +} + +// ProtoToChannel converts a Channel resource from its proto representation. +func ProtoToChannel(p *alphapb.EventarcAlphaChannel) *alpha.Channel { + obj := &alpha.Channel{ + Name: dcl.StringOrNil(p.GetName()), + Uid: dcl.StringOrNil(p.GetUid()), + CreateTime: dcl.StringOrNil(p.GetCreateTime()), + UpdateTime: dcl.StringOrNil(p.GetUpdateTime()), + Provider: dcl.StringOrNil(p.GetProvider()), + PubsubTopic: dcl.StringOrNil(p.GetPubsubTopic()), + State: ProtoToEventarcAlphaChannelStateEnum(p.GetState()), + ActivationToken: dcl.StringOrNil(p.GetActivationToken()), + CryptoKeyName: dcl.StringOrNil(p.GetCryptoKeyName()), + Project: dcl.StringOrNil(p.GetProject()), + Location: dcl.StringOrNil(p.GetLocation()), + } + return obj +} + +// ChannelStateEnumToProto converts a ChannelStateEnum enum to its proto representation. +func EventarcAlphaChannelStateEnumToProto(e *alpha.ChannelStateEnum) alphapb.EventarcAlphaChannelStateEnum { + if e == nil { + return alphapb.EventarcAlphaChannelStateEnum(0) + } + if v, ok := alphapb.EventarcAlphaChannelStateEnum_value["ChannelStateEnum"+string(*e)]; ok { + return alphapb.EventarcAlphaChannelStateEnum(v) + } + return alphapb.EventarcAlphaChannelStateEnum(0) +} + +// ChannelToProto converts a Channel resource to its proto representation. +func ChannelToProto(resource *alpha.Channel) *alphapb.EventarcAlphaChannel { + p := &alphapb.EventarcAlphaChannel{} + p.SetName(dcl.ValueOrEmptyString(resource.Name)) + p.SetUid(dcl.ValueOrEmptyString(resource.Uid)) + p.SetCreateTime(dcl.ValueOrEmptyString(resource.CreateTime)) + p.SetUpdateTime(dcl.ValueOrEmptyString(resource.UpdateTime)) + p.SetProvider(dcl.ValueOrEmptyString(resource.Provider)) + p.SetPubsubTopic(dcl.ValueOrEmptyString(resource.PubsubTopic)) + p.SetState(EventarcAlphaChannelStateEnumToProto(resource.State)) + p.SetActivationToken(dcl.ValueOrEmptyString(resource.ActivationToken)) + p.SetCryptoKeyName(dcl.ValueOrEmptyString(resource.CryptoKeyName)) + p.SetProject(dcl.ValueOrEmptyString(resource.Project)) + p.SetLocation(dcl.ValueOrEmptyString(resource.Location)) + + return p +} + +// applyChannel handles the gRPC request by passing it to the underlying Channel Apply() method. +func (s *ChannelServer) applyChannel(ctx context.Context, c *alpha.Client, request *alphapb.ApplyEventarcAlphaChannelRequest) (*alphapb.EventarcAlphaChannel, error) { + p := ProtoToChannel(request.GetResource()) + res, err := c.ApplyChannel(ctx, p) + if err != nil { + return nil, err + } + r := ChannelToProto(res) + return r, nil +} + +// applyEventarcAlphaChannel handles the gRPC request by passing it to the underlying Channel Apply() method. +func (s *ChannelServer) ApplyEventarcAlphaChannel(ctx context.Context, request *alphapb.ApplyEventarcAlphaChannelRequest) (*alphapb.EventarcAlphaChannel, error) { + cl, err := createConfigChannel(ctx, request.GetServiceAccountFile()) + if err != nil { + return nil, err + } + return s.applyChannel(ctx, cl, request) +} + +// DeleteChannel handles the gRPC request by passing it to the underlying Channel Delete() method. +func (s *ChannelServer) DeleteEventarcAlphaChannel(ctx context.Context, request *alphapb.DeleteEventarcAlphaChannelRequest) (*emptypb.Empty, error) { + + cl, err := createConfigChannel(ctx, request.GetServiceAccountFile()) + if err != nil { + return nil, err + } + return &emptypb.Empty{}, cl.DeleteChannel(ctx, ProtoToChannel(request.GetResource())) + +} + +// ListEventarcAlphaChannel handles the gRPC request by passing it to the underlying ChannelList() method. +func (s *ChannelServer) ListEventarcAlphaChannel(ctx context.Context, request *alphapb.ListEventarcAlphaChannelRequest) (*alphapb.ListEventarcAlphaChannelResponse, error) { + cl, err := createConfigChannel(ctx, request.GetServiceAccountFile()) + if err != nil { + return nil, err + } + + resources, err := cl.ListChannel(ctx, request.GetProject(), request.GetLocation()) + if err != nil { + return nil, err + } + var protos []*alphapb.EventarcAlphaChannel + for _, r := range resources.Items { + rp := ChannelToProto(r) + protos = append(protos, rp) + } + p := &alphapb.ListEventarcAlphaChannelResponse{} + p.SetItems(protos) + return p, nil +} + +func createConfigChannel(ctx context.Context, service_account_file string) (*alpha.Client, error) { + + conf := dcl.NewConfig(dcl.WithUserAgent("dcl-test"), dcl.WithCredentialsFile(service_account_file)) + return alpha.NewClient(conf), nil +} diff --git a/python/services/eventarc/alpha/register.go b/python/services/eventarc/alpha/register.go index 032d2e2e7..adebc9bfb 100755 --- a/python/services/eventarc/alpha/register.go +++ b/python/services/eventarc/alpha/register.go @@ -21,4 +21,5 @@ import ( // RegisterServers registers each resource with the gRPC server. func RegisterServers(s *grpc.Server) { sdkgrpc.RegisterEventarcAlphaTriggerServiceServer(s, &TriggerServer{}) + sdkgrpc.RegisterEventarcAlphaChannelServiceServer(s, &ChannelServer{}) } diff --git a/python/services/eventarc/beta/BUILD b/python/services/eventarc/beta/BUILD index 259552c39..f28fa3f3f 100755 --- a/python/services/eventarc/beta/BUILD +++ b/python/services/eventarc/beta/BUILD @@ -13,4 +13,4 @@ # limitations under the License. load("//:connector_rules.bzl", "connector") -connector(name="eventarc/beta", resources=["trigger"]) +connector(name="eventarc/beta", resources=["trigger","channel"]) diff --git a/python/services/eventarc/beta/channel.py b/python/services/eventarc/beta/channel.py new file mode 100755 index 000000000..03b82f127 --- /dev/null +++ b/python/services/eventarc/beta/channel.py @@ -0,0 +1,153 @@ +# Copyright 2022 Google LLC. All Rights Reserved. +# +# 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. +from connector import channel +from google3.cloud.graphite.mmv2.services.google.eventarc import channel_pb2 +from google3.cloud.graphite.mmv2.services.google.eventarc import channel_pb2_grpc + +from typing import List + + +class Channel(object): + def __init__( + self, + name: str = None, + uid: str = None, + create_time: str = None, + update_time: str = None, + provider: str = None, + pubsub_topic: str = None, + state: str = None, + activation_token: str = None, + crypto_key_name: str = None, + project: str = None, + location: str = None, + service_account_file: str = "", + ): + + channel.initialize() + self.name = name + self.provider = provider + self.crypto_key_name = crypto_key_name + self.project = project + self.location = location + self.service_account_file = service_account_file + + def apply(self): + stub = channel_pb2_grpc.EventarcBetaChannelServiceStub(channel.Channel()) + request = channel_pb2.ApplyEventarcBetaChannelRequest() + if Primitive.to_proto(self.name): + request.resource.name = Primitive.to_proto(self.name) + + if Primitive.to_proto(self.provider): + request.resource.provider = Primitive.to_proto(self.provider) + + if Primitive.to_proto(self.crypto_key_name): + request.resource.crypto_key_name = Primitive.to_proto(self.crypto_key_name) + + if Primitive.to_proto(self.project): + request.resource.project = Primitive.to_proto(self.project) + + if Primitive.to_proto(self.location): + request.resource.location = Primitive.to_proto(self.location) + + request.service_account_file = self.service_account_file + + response = stub.ApplyEventarcBetaChannel(request) + self.name = Primitive.from_proto(response.name) + self.uid = Primitive.from_proto(response.uid) + self.create_time = Primitive.from_proto(response.create_time) + self.update_time = Primitive.from_proto(response.update_time) + self.provider = Primitive.from_proto(response.provider) + self.pubsub_topic = Primitive.from_proto(response.pubsub_topic) + self.state = ChannelStateEnum.from_proto(response.state) + self.activation_token = Primitive.from_proto(response.activation_token) + self.crypto_key_name = Primitive.from_proto(response.crypto_key_name) + self.project = Primitive.from_proto(response.project) + self.location = Primitive.from_proto(response.location) + + def delete(self): + stub = channel_pb2_grpc.EventarcBetaChannelServiceStub(channel.Channel()) + request = channel_pb2.DeleteEventarcBetaChannelRequest() + request.service_account_file = self.service_account_file + if Primitive.to_proto(self.name): + request.resource.name = Primitive.to_proto(self.name) + + if Primitive.to_proto(self.provider): + request.resource.provider = Primitive.to_proto(self.provider) + + if Primitive.to_proto(self.crypto_key_name): + request.resource.crypto_key_name = Primitive.to_proto(self.crypto_key_name) + + if Primitive.to_proto(self.project): + request.resource.project = Primitive.to_proto(self.project) + + if Primitive.to_proto(self.location): + request.resource.location = Primitive.to_proto(self.location) + + response = stub.DeleteEventarcBetaChannel(request) + + @classmethod + def list(self, project, location, service_account_file=""): + stub = channel_pb2_grpc.EventarcBetaChannelServiceStub(channel.Channel()) + request = channel_pb2.ListEventarcBetaChannelRequest() + request.service_account_file = service_account_file + request.Project = project + + request.Location = location + + return stub.ListEventarcBetaChannel(request).items + + def to_proto(self): + resource = channel_pb2.EventarcBetaChannel() + if Primitive.to_proto(self.name): + resource.name = Primitive.to_proto(self.name) + if Primitive.to_proto(self.provider): + resource.provider = Primitive.to_proto(self.provider) + if Primitive.to_proto(self.crypto_key_name): + resource.crypto_key_name = Primitive.to_proto(self.crypto_key_name) + if Primitive.to_proto(self.project): + resource.project = Primitive.to_proto(self.project) + if Primitive.to_proto(self.location): + resource.location = Primitive.to_proto(self.location) + return resource + + +class ChannelStateEnum(object): + @classmethod + def to_proto(self, resource): + if not resource: + return resource + return channel_pb2.EventarcBetaChannelStateEnum.Value( + "EventarcBetaChannelStateEnum%s" % resource + ) + + @classmethod + def from_proto(self, resource): + if not resource: + return resource + return channel_pb2.EventarcBetaChannelStateEnum.Name(resource)[ + len("EventarcBetaChannelStateEnum") : + ] + + +class Primitive(object): + @classmethod + def to_proto(self, s): + if not s: + return "" + return s + + @classmethod + def from_proto(self, s): + return s diff --git a/python/services/eventarc/beta/channel_server.go b/python/services/eventarc/beta/channel_server.go new file mode 100755 index 000000000..00561a13e --- /dev/null +++ b/python/services/eventarc/beta/channel_server.go @@ -0,0 +1,142 @@ +// Copyright 2022 Google LLC. All Rights Reserved. +// +// 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 server + +import ( + "context" + "github.com/GoogleCloudPlatform/declarative-resource-client-library/dcl" + emptypb "github.com/GoogleCloudPlatform/declarative-resource-client-library/python/proto/empty_go_proto" + betapb "github.com/GoogleCloudPlatform/declarative-resource-client-library/python/proto/eventarc/beta/eventarc_beta_go_proto" + "github.com/GoogleCloudPlatform/declarative-resource-client-library/services/google/eventarc/beta" +) + +// ChannelServer implements the gRPC interface for Channel. +type ChannelServer struct{} + +// ProtoToChannelStateEnum converts a ChannelStateEnum enum from its proto representation. +func ProtoToEventarcBetaChannelStateEnum(e betapb.EventarcBetaChannelStateEnum) *beta.ChannelStateEnum { + if e == 0 { + return nil + } + if n, ok := betapb.EventarcBetaChannelStateEnum_name[int32(e)]; ok { + e := beta.ChannelStateEnum(n[len("EventarcBetaChannelStateEnum"):]) + return &e + } + return nil +} + +// ProtoToChannel converts a Channel resource from its proto representation. +func ProtoToChannel(p *betapb.EventarcBetaChannel) *beta.Channel { + obj := &beta.Channel{ + Name: dcl.StringOrNil(p.GetName()), + Uid: dcl.StringOrNil(p.GetUid()), + CreateTime: dcl.StringOrNil(p.GetCreateTime()), + UpdateTime: dcl.StringOrNil(p.GetUpdateTime()), + Provider: dcl.StringOrNil(p.GetProvider()), + PubsubTopic: dcl.StringOrNil(p.GetPubsubTopic()), + State: ProtoToEventarcBetaChannelStateEnum(p.GetState()), + ActivationToken: dcl.StringOrNil(p.GetActivationToken()), + CryptoKeyName: dcl.StringOrNil(p.GetCryptoKeyName()), + Project: dcl.StringOrNil(p.GetProject()), + Location: dcl.StringOrNil(p.GetLocation()), + } + return obj +} + +// ChannelStateEnumToProto converts a ChannelStateEnum enum to its proto representation. +func EventarcBetaChannelStateEnumToProto(e *beta.ChannelStateEnum) betapb.EventarcBetaChannelStateEnum { + if e == nil { + return betapb.EventarcBetaChannelStateEnum(0) + } + if v, ok := betapb.EventarcBetaChannelStateEnum_value["ChannelStateEnum"+string(*e)]; ok { + return betapb.EventarcBetaChannelStateEnum(v) + } + return betapb.EventarcBetaChannelStateEnum(0) +} + +// ChannelToProto converts a Channel resource to its proto representation. +func ChannelToProto(resource *beta.Channel) *betapb.EventarcBetaChannel { + p := &betapb.EventarcBetaChannel{} + p.SetName(dcl.ValueOrEmptyString(resource.Name)) + p.SetUid(dcl.ValueOrEmptyString(resource.Uid)) + p.SetCreateTime(dcl.ValueOrEmptyString(resource.CreateTime)) + p.SetUpdateTime(dcl.ValueOrEmptyString(resource.UpdateTime)) + p.SetProvider(dcl.ValueOrEmptyString(resource.Provider)) + p.SetPubsubTopic(dcl.ValueOrEmptyString(resource.PubsubTopic)) + p.SetState(EventarcBetaChannelStateEnumToProto(resource.State)) + p.SetActivationToken(dcl.ValueOrEmptyString(resource.ActivationToken)) + p.SetCryptoKeyName(dcl.ValueOrEmptyString(resource.CryptoKeyName)) + p.SetProject(dcl.ValueOrEmptyString(resource.Project)) + p.SetLocation(dcl.ValueOrEmptyString(resource.Location)) + + return p +} + +// applyChannel handles the gRPC request by passing it to the underlying Channel Apply() method. +func (s *ChannelServer) applyChannel(ctx context.Context, c *beta.Client, request *betapb.ApplyEventarcBetaChannelRequest) (*betapb.EventarcBetaChannel, error) { + p := ProtoToChannel(request.GetResource()) + res, err := c.ApplyChannel(ctx, p) + if err != nil { + return nil, err + } + r := ChannelToProto(res) + return r, nil +} + +// applyEventarcBetaChannel handles the gRPC request by passing it to the underlying Channel Apply() method. +func (s *ChannelServer) ApplyEventarcBetaChannel(ctx context.Context, request *betapb.ApplyEventarcBetaChannelRequest) (*betapb.EventarcBetaChannel, error) { + cl, err := createConfigChannel(ctx, request.GetServiceAccountFile()) + if err != nil { + return nil, err + } + return s.applyChannel(ctx, cl, request) +} + +// DeleteChannel handles the gRPC request by passing it to the underlying Channel Delete() method. +func (s *ChannelServer) DeleteEventarcBetaChannel(ctx context.Context, request *betapb.DeleteEventarcBetaChannelRequest) (*emptypb.Empty, error) { + + cl, err := createConfigChannel(ctx, request.GetServiceAccountFile()) + if err != nil { + return nil, err + } + return &emptypb.Empty{}, cl.DeleteChannel(ctx, ProtoToChannel(request.GetResource())) + +} + +// ListEventarcBetaChannel handles the gRPC request by passing it to the underlying ChannelList() method. +func (s *ChannelServer) ListEventarcBetaChannel(ctx context.Context, request *betapb.ListEventarcBetaChannelRequest) (*betapb.ListEventarcBetaChannelResponse, error) { + cl, err := createConfigChannel(ctx, request.GetServiceAccountFile()) + if err != nil { + return nil, err + } + + resources, err := cl.ListChannel(ctx, request.GetProject(), request.GetLocation()) + if err != nil { + return nil, err + } + var protos []*betapb.EventarcBetaChannel + for _, r := range resources.Items { + rp := ChannelToProto(r) + protos = append(protos, rp) + } + p := &betapb.ListEventarcBetaChannelResponse{} + p.SetItems(protos) + return p, nil +} + +func createConfigChannel(ctx context.Context, service_account_file string) (*beta.Client, error) { + + conf := dcl.NewConfig(dcl.WithUserAgent("dcl-test"), dcl.WithCredentialsFile(service_account_file)) + return beta.NewClient(conf), nil +} diff --git a/python/services/eventarc/beta/register.go b/python/services/eventarc/beta/register.go index 17da4976f..e4ffc39fb 100755 --- a/python/services/eventarc/beta/register.go +++ b/python/services/eventarc/beta/register.go @@ -21,4 +21,5 @@ import ( // RegisterServers registers each resource with the gRPC server. func RegisterServers(s *grpc.Server) { sdkgrpc.RegisterEventarcBetaTriggerServiceServer(s, &TriggerServer{}) + sdkgrpc.RegisterEventarcBetaChannelServiceServer(s, &ChannelServer{}) } diff --git a/python/services/eventarc/channel.py b/python/services/eventarc/channel.py new file mode 100755 index 000000000..f58be4eaa --- /dev/null +++ b/python/services/eventarc/channel.py @@ -0,0 +1,153 @@ +# Copyright 2022 Google LLC. All Rights Reserved. +# +# 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. +from connector import channel +from google3.cloud.graphite.mmv2.services.google.eventarc import channel_pb2 +from google3.cloud.graphite.mmv2.services.google.eventarc import channel_pb2_grpc + +from typing import List + + +class Channel(object): + def __init__( + self, + name: str = None, + uid: str = None, + create_time: str = None, + update_time: str = None, + provider: str = None, + pubsub_topic: str = None, + state: str = None, + activation_token: str = None, + crypto_key_name: str = None, + project: str = None, + location: str = None, + service_account_file: str = "", + ): + + channel.initialize() + self.name = name + self.provider = provider + self.crypto_key_name = crypto_key_name + self.project = project + self.location = location + self.service_account_file = service_account_file + + def apply(self): + stub = channel_pb2_grpc.EventarcChannelServiceStub(channel.Channel()) + request = channel_pb2.ApplyEventarcChannelRequest() + if Primitive.to_proto(self.name): + request.resource.name = Primitive.to_proto(self.name) + + if Primitive.to_proto(self.provider): + request.resource.provider = Primitive.to_proto(self.provider) + + if Primitive.to_proto(self.crypto_key_name): + request.resource.crypto_key_name = Primitive.to_proto(self.crypto_key_name) + + if Primitive.to_proto(self.project): + request.resource.project = Primitive.to_proto(self.project) + + if Primitive.to_proto(self.location): + request.resource.location = Primitive.to_proto(self.location) + + request.service_account_file = self.service_account_file + + response = stub.ApplyEventarcChannel(request) + self.name = Primitive.from_proto(response.name) + self.uid = Primitive.from_proto(response.uid) + self.create_time = Primitive.from_proto(response.create_time) + self.update_time = Primitive.from_proto(response.update_time) + self.provider = Primitive.from_proto(response.provider) + self.pubsub_topic = Primitive.from_proto(response.pubsub_topic) + self.state = ChannelStateEnum.from_proto(response.state) + self.activation_token = Primitive.from_proto(response.activation_token) + self.crypto_key_name = Primitive.from_proto(response.crypto_key_name) + self.project = Primitive.from_proto(response.project) + self.location = Primitive.from_proto(response.location) + + def delete(self): + stub = channel_pb2_grpc.EventarcChannelServiceStub(channel.Channel()) + request = channel_pb2.DeleteEventarcChannelRequest() + request.service_account_file = self.service_account_file + if Primitive.to_proto(self.name): + request.resource.name = Primitive.to_proto(self.name) + + if Primitive.to_proto(self.provider): + request.resource.provider = Primitive.to_proto(self.provider) + + if Primitive.to_proto(self.crypto_key_name): + request.resource.crypto_key_name = Primitive.to_proto(self.crypto_key_name) + + if Primitive.to_proto(self.project): + request.resource.project = Primitive.to_proto(self.project) + + if Primitive.to_proto(self.location): + request.resource.location = Primitive.to_proto(self.location) + + response = stub.DeleteEventarcChannel(request) + + @classmethod + def list(self, project, location, service_account_file=""): + stub = channel_pb2_grpc.EventarcChannelServiceStub(channel.Channel()) + request = channel_pb2.ListEventarcChannelRequest() + request.service_account_file = service_account_file + request.Project = project + + request.Location = location + + return stub.ListEventarcChannel(request).items + + def to_proto(self): + resource = channel_pb2.EventarcChannel() + if Primitive.to_proto(self.name): + resource.name = Primitive.to_proto(self.name) + if Primitive.to_proto(self.provider): + resource.provider = Primitive.to_proto(self.provider) + if Primitive.to_proto(self.crypto_key_name): + resource.crypto_key_name = Primitive.to_proto(self.crypto_key_name) + if Primitive.to_proto(self.project): + resource.project = Primitive.to_proto(self.project) + if Primitive.to_proto(self.location): + resource.location = Primitive.to_proto(self.location) + return resource + + +class ChannelStateEnum(object): + @classmethod + def to_proto(self, resource): + if not resource: + return resource + return channel_pb2.EventarcChannelStateEnum.Value( + "EventarcChannelStateEnum%s" % resource + ) + + @classmethod + def from_proto(self, resource): + if not resource: + return resource + return channel_pb2.EventarcChannelStateEnum.Name(resource)[ + len("EventarcChannelStateEnum") : + ] + + +class Primitive(object): + @classmethod + def to_proto(self, s): + if not s: + return "" + return s + + @classmethod + def from_proto(self, s): + return s diff --git a/python/services/eventarc/channel_server.go b/python/services/eventarc/channel_server.go new file mode 100755 index 000000000..5b136409f --- /dev/null +++ b/python/services/eventarc/channel_server.go @@ -0,0 +1,142 @@ +// Copyright 2022 Google LLC. All Rights Reserved. +// +// 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 server + +import ( + "context" + "github.com/GoogleCloudPlatform/declarative-resource-client-library/dcl" + emptypb "github.com/GoogleCloudPlatform/declarative-resource-client-library/python/proto/empty_go_proto" + eventarcpb "github.com/GoogleCloudPlatform/declarative-resource-client-library/python/proto/eventarc/eventarc_go_proto" + "github.com/GoogleCloudPlatform/declarative-resource-client-library/services/google/eventarc" +) + +// ChannelServer implements the gRPC interface for Channel. +type ChannelServer struct{} + +// ProtoToChannelStateEnum converts a ChannelStateEnum enum from its proto representation. +func ProtoToEventarcChannelStateEnum(e eventarcpb.EventarcChannelStateEnum) *eventarc.ChannelStateEnum { + if e == 0 { + return nil + } + if n, ok := eventarcpb.EventarcChannelStateEnum_name[int32(e)]; ok { + e := eventarc.ChannelStateEnum(n[len("EventarcChannelStateEnum"):]) + return &e + } + return nil +} + +// ProtoToChannel converts a Channel resource from its proto representation. +func ProtoToChannel(p *eventarcpb.EventarcChannel) *eventarc.Channel { + obj := &eventarc.Channel{ + Name: dcl.StringOrNil(p.GetName()), + Uid: dcl.StringOrNil(p.GetUid()), + CreateTime: dcl.StringOrNil(p.GetCreateTime()), + UpdateTime: dcl.StringOrNil(p.GetUpdateTime()), + Provider: dcl.StringOrNil(p.GetProvider()), + PubsubTopic: dcl.StringOrNil(p.GetPubsubTopic()), + State: ProtoToEventarcChannelStateEnum(p.GetState()), + ActivationToken: dcl.StringOrNil(p.GetActivationToken()), + CryptoKeyName: dcl.StringOrNil(p.GetCryptoKeyName()), + Project: dcl.StringOrNil(p.GetProject()), + Location: dcl.StringOrNil(p.GetLocation()), + } + return obj +} + +// ChannelStateEnumToProto converts a ChannelStateEnum enum to its proto representation. +func EventarcChannelStateEnumToProto(e *eventarc.ChannelStateEnum) eventarcpb.EventarcChannelStateEnum { + if e == nil { + return eventarcpb.EventarcChannelStateEnum(0) + } + if v, ok := eventarcpb.EventarcChannelStateEnum_value["ChannelStateEnum"+string(*e)]; ok { + return eventarcpb.EventarcChannelStateEnum(v) + } + return eventarcpb.EventarcChannelStateEnum(0) +} + +// ChannelToProto converts a Channel resource to its proto representation. +func ChannelToProto(resource *eventarc.Channel) *eventarcpb.EventarcChannel { + p := &eventarcpb.EventarcChannel{} + p.SetName(dcl.ValueOrEmptyString(resource.Name)) + p.SetUid(dcl.ValueOrEmptyString(resource.Uid)) + p.SetCreateTime(dcl.ValueOrEmptyString(resource.CreateTime)) + p.SetUpdateTime(dcl.ValueOrEmptyString(resource.UpdateTime)) + p.SetProvider(dcl.ValueOrEmptyString(resource.Provider)) + p.SetPubsubTopic(dcl.ValueOrEmptyString(resource.PubsubTopic)) + p.SetState(EventarcChannelStateEnumToProto(resource.State)) + p.SetActivationToken(dcl.ValueOrEmptyString(resource.ActivationToken)) + p.SetCryptoKeyName(dcl.ValueOrEmptyString(resource.CryptoKeyName)) + p.SetProject(dcl.ValueOrEmptyString(resource.Project)) + p.SetLocation(dcl.ValueOrEmptyString(resource.Location)) + + return p +} + +// applyChannel handles the gRPC request by passing it to the underlying Channel Apply() method. +func (s *ChannelServer) applyChannel(ctx context.Context, c *eventarc.Client, request *eventarcpb.ApplyEventarcChannelRequest) (*eventarcpb.EventarcChannel, error) { + p := ProtoToChannel(request.GetResource()) + res, err := c.ApplyChannel(ctx, p) + if err != nil { + return nil, err + } + r := ChannelToProto(res) + return r, nil +} + +// applyEventarcChannel handles the gRPC request by passing it to the underlying Channel Apply() method. +func (s *ChannelServer) ApplyEventarcChannel(ctx context.Context, request *eventarcpb.ApplyEventarcChannelRequest) (*eventarcpb.EventarcChannel, error) { + cl, err := createConfigChannel(ctx, request.GetServiceAccountFile()) + if err != nil { + return nil, err + } + return s.applyChannel(ctx, cl, request) +} + +// DeleteChannel handles the gRPC request by passing it to the underlying Channel Delete() method. +func (s *ChannelServer) DeleteEventarcChannel(ctx context.Context, request *eventarcpb.DeleteEventarcChannelRequest) (*emptypb.Empty, error) { + + cl, err := createConfigChannel(ctx, request.GetServiceAccountFile()) + if err != nil { + return nil, err + } + return &emptypb.Empty{}, cl.DeleteChannel(ctx, ProtoToChannel(request.GetResource())) + +} + +// ListEventarcChannel handles the gRPC request by passing it to the underlying ChannelList() method. +func (s *ChannelServer) ListEventarcChannel(ctx context.Context, request *eventarcpb.ListEventarcChannelRequest) (*eventarcpb.ListEventarcChannelResponse, error) { + cl, err := createConfigChannel(ctx, request.GetServiceAccountFile()) + if err != nil { + return nil, err + } + + resources, err := cl.ListChannel(ctx, request.GetProject(), request.GetLocation()) + if err != nil { + return nil, err + } + var protos []*eventarcpb.EventarcChannel + for _, r := range resources.Items { + rp := ChannelToProto(r) + protos = append(protos, rp) + } + p := &eventarcpb.ListEventarcChannelResponse{} + p.SetItems(protos) + return p, nil +} + +func createConfigChannel(ctx context.Context, service_account_file string) (*eventarc.Client, error) { + + conf := dcl.NewConfig(dcl.WithUserAgent("dcl-test"), dcl.WithCredentialsFile(service_account_file)) + return eventarc.NewClient(conf), nil +} diff --git a/python/services/eventarc/register.go b/python/services/eventarc/register.go index 0e92cc9eb..8f1419fa8 100755 --- a/python/services/eventarc/register.go +++ b/python/services/eventarc/register.go @@ -21,4 +21,5 @@ import ( // RegisterServers registers each resource with the gRPC server. func RegisterServers(s *grpc.Server) { sdkgrpc.RegisterEventarcTriggerServiceServer(s, &TriggerServer{}) + sdkgrpc.RegisterEventarcChannelServiceServer(s, &ChannelServer{}) } diff --git a/services/directory.go b/services/directory.go index b0e0392e2..50eda6758 100755 --- a/services/directory.go +++ b/services/directory.go @@ -326,6 +326,8 @@ func Services() *Directory { d.AddResource("ga", "dlp", "StoredInfoType", dlp.YAML_stored_info_type) d.AddResource("ga", "eventarc", dcl.TitleToSnakeCase("Trigger"), eventarc.YAML_trigger) d.AddResource("ga", "eventarc", "Trigger", eventarc.YAML_trigger) + d.AddResource("ga", "eventarc", dcl.TitleToSnakeCase("Channel"), eventarc.YAML_channel) + d.AddResource("ga", "eventarc", "Channel", eventarc.YAML_channel) d.AddResource("ga", "filestore", dcl.TitleToSnakeCase("Instance"), filestore.YAML_instance) d.AddResource("ga", "filestore", "Instance", filestore.YAML_instance) d.AddResource("ga", "firebaserules", dcl.TitleToSnakeCase("Ruleset"), firebaserules.YAML_ruleset) @@ -548,6 +550,8 @@ func Services() *Directory { d.AddResource("beta", "dlp", "StoredInfoType", dlp_beta.YAML_stored_info_type) d.AddResource("beta", "eventarc", dcl.TitleToSnakeCase("Trigger"), eventarc_beta.YAML_trigger) d.AddResource("beta", "eventarc", "Trigger", eventarc_beta.YAML_trigger) + d.AddResource("beta", "eventarc", dcl.TitleToSnakeCase("Channel"), eventarc_beta.YAML_channel) + d.AddResource("beta", "eventarc", "Channel", eventarc_beta.YAML_channel) d.AddResource("beta", "filestore", dcl.TitleToSnakeCase("Instance"), filestore_beta.YAML_instance) d.AddResource("beta", "filestore", "Instance", filestore_beta.YAML_instance) d.AddResource("beta", "filestore", dcl.TitleToSnakeCase("Backup"), filestore_beta.YAML_backup) @@ -816,6 +820,8 @@ func Services() *Directory { d.AddResource("alpha", "dlp", "StoredInfoType", dlp_alpha.YAML_stored_info_type) d.AddResource("alpha", "eventarc", dcl.TitleToSnakeCase("Trigger"), eventarc_alpha.YAML_trigger) d.AddResource("alpha", "eventarc", "Trigger", eventarc_alpha.YAML_trigger) + d.AddResource("alpha", "eventarc", dcl.TitleToSnakeCase("Channel"), eventarc_alpha.YAML_channel) + d.AddResource("alpha", "eventarc", "Channel", eventarc_alpha.YAML_channel) d.AddResource("alpha", "filestore", dcl.TitleToSnakeCase("Instance"), filestore_alpha.YAML_instance) d.AddResource("alpha", "filestore", "Instance", filestore_alpha.YAML_instance) d.AddResource("alpha", "filestore", dcl.TitleToSnakeCase("Backup"), filestore_alpha.YAML_backup) diff --git a/services/google/eventarc/alpha/channel.go b/services/google/eventarc/alpha/channel.go new file mode 100755 index 000000000..d552923f2 --- /dev/null +++ b/services/google/eventarc/alpha/channel.go @@ -0,0 +1,436 @@ +// Copyright 2022 Google LLC. All Rights Reserved. +// +// 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 alpha + +import ( + "context" + "fmt" + "time" + + "google.golang.org/api/googleapi" + "github.com/GoogleCloudPlatform/declarative-resource-client-library/dcl" +) + +type Channel struct { + Name *string `json:"name"` + Uid *string `json:"uid"` + CreateTime *string `json:"createTime"` + UpdateTime *string `json:"updateTime"` + Provider *string `json:"provider"` + PubsubTopic *string `json:"pubsubTopic"` + State *ChannelStateEnum `json:"state"` + ActivationToken *string `json:"activationToken"` + CryptoKeyName *string `json:"cryptoKeyName"` + Project *string `json:"project"` + Location *string `json:"location"` +} + +func (r *Channel) String() string { + return dcl.SprintResource(r) +} + +// The enum ChannelStateEnum. +type ChannelStateEnum string + +// ChannelStateEnumRef returns a *ChannelStateEnum with the value of string s +// If the empty string is provided, nil is returned. +func ChannelStateEnumRef(s string) *ChannelStateEnum { + v := ChannelStateEnum(s) + return &v +} + +func (v ChannelStateEnum) Validate() error { + if string(v) == "" { + // Empty enum is okay. + return nil + } + for _, s := range []string{"STATE_UNSPECIFIED", "PENDING", "ACTIVE", "INACTIVE"} { + if string(v) == s { + return nil + } + } + return &dcl.EnumInvalidError{ + Enum: "ChannelStateEnum", + Value: string(v), + Valid: []string{}, + } +} + +// Describe returns a simple description of this resource to ensure that automated tools +// can identify it. +func (r *Channel) Describe() dcl.ServiceTypeVersion { + return dcl.ServiceTypeVersion{ + Service: "eventarc", + Type: "Channel", + Version: "alpha", + } +} + +func (r *Channel) ID() (string, error) { + if err := extractChannelFields(r); err != nil { + return "", err + } + nr := r.urlNormalized() + params := map[string]interface{}{ + "name": dcl.ValueOrEmptyString(nr.Name), + "uid": dcl.ValueOrEmptyString(nr.Uid), + "create_time": dcl.ValueOrEmptyString(nr.CreateTime), + "update_time": dcl.ValueOrEmptyString(nr.UpdateTime), + "provider": dcl.ValueOrEmptyString(nr.Provider), + "pubsub_topic": dcl.ValueOrEmptyString(nr.PubsubTopic), + "state": dcl.ValueOrEmptyString(nr.State), + "activation_token": dcl.ValueOrEmptyString(nr.ActivationToken), + "crypto_key_name": dcl.ValueOrEmptyString(nr.CryptoKeyName), + "project": dcl.ValueOrEmptyString(nr.Project), + "location": dcl.ValueOrEmptyString(nr.Location), + } + return dcl.Nprintf("projects/{{project}}/locations/{{location}}/channels/{{name}}", params), nil +} + +const ChannelMaxPage = -1 + +type ChannelList struct { + Items []*Channel + + nextToken string + + pageSize int32 + + resource *Channel +} + +func (l *ChannelList) HasNext() bool { + return l.nextToken != "" +} + +func (l *ChannelList) Next(ctx context.Context, c *Client) error { + ctx, cancel := context.WithTimeout(ctx, c.Config.TimeoutOr(0*time.Second)) + defer cancel() + + if !l.HasNext() { + return fmt.Errorf("no next page") + } + items, token, err := c.listChannel(ctx, l.resource, l.nextToken, l.pageSize) + if err != nil { + return err + } + l.Items = items + l.nextToken = token + return err +} + +func (c *Client) ListChannel(ctx context.Context, project, location string) (*ChannelList, error) { + ctx = dcl.ContextWithRequestID(ctx) + c = NewClient(c.Config.Clone(dcl.WithCodeRetryability(map[int]dcl.Retryability{ + 403: dcl.Retryability{ + Retryable: true, + Pattern: "", + Timeout: 10000000000, + }, + }))) + ctx, cancel := context.WithTimeout(ctx, c.Config.TimeoutOr(0*time.Second)) + defer cancel() + + return c.ListChannelWithMaxResults(ctx, project, location, ChannelMaxPage) + +} + +func (c *Client) ListChannelWithMaxResults(ctx context.Context, project, location string, pageSize int32) (*ChannelList, error) { + ctx, cancel := context.WithTimeout(ctx, c.Config.TimeoutOr(0*time.Second)) + defer cancel() + + // Create a resource object so that we can use proper url normalization methods. + r := &Channel{ + Project: &project, + Location: &location, + } + items, token, err := c.listChannel(ctx, r, "", pageSize) + if err != nil { + return nil, err + } + return &ChannelList{ + Items: items, + nextToken: token, + pageSize: pageSize, + resource: r, + }, nil +} + +func (c *Client) GetChannel(ctx context.Context, r *Channel) (*Channel, error) { + ctx = dcl.ContextWithRequestID(ctx) + c = NewClient(c.Config.Clone(dcl.WithCodeRetryability(map[int]dcl.Retryability{ + 403: dcl.Retryability{ + Retryable: true, + Pattern: "", + Timeout: 10000000000, + }, + }))) + ctx, cancel := context.WithTimeout(ctx, c.Config.TimeoutOr(0*time.Second)) + defer cancel() + + // This is *purposefully* supressing errors. + // This function is used with url-normalized values + not URL normalized values. + // URL Normalized values will throw unintentional errors, since those values are not of the proper parent form. + extractChannelFields(r) + + b, err := c.getChannelRaw(ctx, r) + if err != nil { + if dcl.IsNotFound(err) { + return nil, &googleapi.Error{ + Code: 404, + Message: err.Error(), + } + } + return nil, err + } + result, err := unmarshalChannel(b, c, r) + if err != nil { + return nil, err + } + result.Project = r.Project + result.Location = r.Location + result.Name = r.Name + + c.Config.Logger.InfoWithContextf(ctx, "Retrieved raw result state: %v", result) + c.Config.Logger.InfoWithContextf(ctx, "Canonicalizing with specified state: %v", r) + result, err = canonicalizeChannelNewState(c, result, r) + if err != nil { + return nil, err + } + if err := postReadExtractChannelFields(result); err != nil { + return result, err + } + c.Config.Logger.InfoWithContextf(ctx, "Created result state: %v", result) + + return result, nil +} + +func (c *Client) DeleteChannel(ctx context.Context, r *Channel) error { + ctx = dcl.ContextWithRequestID(ctx) + c = NewClient(c.Config.Clone(dcl.WithCodeRetryability(map[int]dcl.Retryability{ + 403: dcl.Retryability{ + Retryable: true, + Pattern: "", + Timeout: 10000000000, + }, + }))) + ctx, cancel := context.WithTimeout(ctx, c.Config.TimeoutOr(0*time.Second)) + defer cancel() + + if r == nil { + return fmt.Errorf("Channel resource is nil") + } + c.Config.Logger.InfoWithContext(ctx, "Deleting Channel...") + deleteOp := deleteChannelOperation{} + return deleteOp.do(ctx, r, c) +} + +// DeleteAllChannel deletes all resources that the filter functions returns true on. +func (c *Client) DeleteAllChannel(ctx context.Context, project, location string, filter func(*Channel) bool) error { + listObj, err := c.ListChannel(ctx, project, location) + if err != nil { + return err + } + + err = c.deleteAllChannel(ctx, filter, listObj.Items) + if err != nil { + return err + } + for listObj.HasNext() { + err = listObj.Next(ctx, c) + if err != nil { + return nil + } + err = c.deleteAllChannel(ctx, filter, listObj.Items) + if err != nil { + return err + } + } + return nil +} + +func (c *Client) ApplyChannel(ctx context.Context, rawDesired *Channel, opts ...dcl.ApplyOption) (*Channel, error) { + ctx, cancel := context.WithTimeout(ctx, c.Config.TimeoutOr(0*time.Second)) + defer cancel() + + ctx = dcl.ContextWithRequestID(ctx) + c = NewClient(c.Config.Clone(dcl.WithCodeRetryability(map[int]dcl.Retryability{ + 403: dcl.Retryability{ + Retryable: true, + Pattern: "", + Timeout: 10000000000, + }, + }))) + var resultNewState *Channel + err := dcl.Do(ctx, func(ctx context.Context) (*dcl.RetryDetails, error) { + newState, err := applyChannelHelper(c, ctx, rawDesired, opts...) + resultNewState = newState + if err != nil { + // If the error is 409, there is conflict in resource update. + // Here we want to apply changes based on latest state. + if dcl.IsConflictError(err) { + return &dcl.RetryDetails{}, dcl.OperationNotDone{Err: err} + } + return nil, err + } + return nil, nil + }, c.Config.RetryProvider) + return resultNewState, err +} + +func applyChannelHelper(c *Client, ctx context.Context, rawDesired *Channel, opts ...dcl.ApplyOption) (*Channel, error) { + c.Config.Logger.InfoWithContext(ctx, "Beginning ApplyChannel...") + c.Config.Logger.InfoWithContextf(ctx, "User specified desired state: %v", rawDesired) + + // 1.1: Validation of user-specified fields in desired state. + if err := rawDesired.validate(); err != nil { + return nil, err + } + + if err := extractChannelFields(rawDesired); err != nil { + return nil, err + } + + initial, desired, fieldDiffs, err := c.channelDiffsForRawDesired(ctx, rawDesired, opts...) + if err != nil { + return nil, fmt.Errorf("failed to create a diff: %w", err) + } + + diffs, err := convertFieldDiffsToChannelDiffs(c.Config, fieldDiffs, opts) + if err != nil { + return nil, err + } + + // TODO(magic-modules-eng): 2.2 Feasibility check (all updates are feasible so far). + + // 2.3: Lifecycle Directive Check + var create bool + lp := dcl.FetchLifecycleParams(opts) + if initial == nil { + if dcl.HasLifecycleParam(lp, dcl.BlockCreation) { + return nil, dcl.ApplyInfeasibleError{Message: fmt.Sprintf("Creation blocked by lifecycle params: %#v.", desired)} + } + create = true + } else if dcl.HasLifecycleParam(lp, dcl.BlockAcquire) { + return nil, dcl.ApplyInfeasibleError{ + Message: fmt.Sprintf("Resource already exists - apply blocked by lifecycle params: %#v.", initial), + } + } else { + for _, d := range diffs { + if d.RequiresRecreate { + return nil, dcl.ApplyInfeasibleError{ + Message: fmt.Sprintf("infeasible update: (%v) would require recreation", d), + } + } + if dcl.HasLifecycleParam(lp, dcl.BlockModification) { + return nil, dcl.ApplyInfeasibleError{Message: fmt.Sprintf("Modification blocked, diff (%v) unresolvable.", d)} + } + } + } + + // 2.4 Imperative Request Planning + var ops []channelApiOperation + if create { + ops = append(ops, &createChannelOperation{}) + } else { + for _, d := range diffs { + ops = append(ops, d.UpdateOp) + } + } + c.Config.Logger.InfoWithContextf(ctx, "Created plan: %#v", ops) + + // 2.5 Request Actuation + for _, op := range ops { + c.Config.Logger.InfoWithContextf(ctx, "Performing operation %T %+v", op, op) + if err := op.do(ctx, desired, c); err != nil { + c.Config.Logger.InfoWithContextf(ctx, "Failed operation %T %+v: %v", op, op, err) + return nil, err + } + c.Config.Logger.InfoWithContextf(ctx, "Finished operation %T %+v", op, op) + } + return applyChannelDiff(c, ctx, desired, rawDesired, ops, opts...) +} + +func applyChannelDiff(c *Client, ctx context.Context, desired *Channel, rawDesired *Channel, ops []channelApiOperation, opts ...dcl.ApplyOption) (*Channel, error) { + // 3.1, 3.2a Retrieval of raw new state & canonicalization with desired state + c.Config.Logger.InfoWithContext(ctx, "Retrieving raw new state...") + rawNew, err := c.GetChannel(ctx, desired) + if err != nil { + return nil, err + } + // Get additional values from the first response. + // These values should be merged into the newState above. + if len(ops) > 0 { + lastOp := ops[len(ops)-1] + if o, ok := lastOp.(*createChannelOperation); ok { + if r, hasR := o.FirstResponse(); hasR { + + c.Config.Logger.InfoWithContext(ctx, "Retrieving raw new state from operation...") + + fullResp, err := unmarshalMapChannel(r, c, rawDesired) + if err != nil { + return nil, err + } + + rawNew, err = canonicalizeChannelNewState(c, rawNew, fullResp) + if err != nil { + return nil, err + } + } + } + } + + c.Config.Logger.InfoWithContextf(ctx, "Canonicalizing with raw desired state: %v", rawDesired) + // 3.2b Canonicalization of raw new state using raw desired state + newState, err := canonicalizeChannelNewState(c, rawNew, rawDesired) + if err != nil { + return rawNew, err + } + + c.Config.Logger.InfoWithContextf(ctx, "Created canonical new state: %v", newState) + // 3.3 Comparison of the new state and raw desired state. + // TODO(magic-modules-eng): EVENTUALLY_CONSISTENT_UPDATE + newDesired, err := canonicalizeChannelDesiredState(rawDesired, newState) + if err != nil { + return newState, err + } + + if err := postReadExtractChannelFields(newState); err != nil { + return newState, err + } + + // Need to ensure any transformations made here match acceptably in differ. + if err := postReadExtractChannelFields(newDesired); err != nil { + return newState, err + } + + c.Config.Logger.InfoWithContextf(ctx, "Diffing using canonicalized desired state: %v", newDesired) + newDiffs, err := diffChannel(c, newDesired, newState) + if err != nil { + return newState, err + } + + if len(newDiffs) == 0 { + c.Config.Logger.InfoWithContext(ctx, "No diffs found. Apply was successful.") + } else { + c.Config.Logger.InfoWithContextf(ctx, "Found diffs: %v", newDiffs) + diffMessages := make([]string, len(newDiffs)) + for i, d := range newDiffs { + diffMessages[i] = fmt.Sprintf("%v", d) + } + return newState, dcl.DiffAfterApplyError{Diffs: diffMessages} + } + c.Config.Logger.InfoWithContext(ctx, "Done Apply.") + return newState, nil +} diff --git a/services/google/eventarc/alpha/channel.yaml b/services/google/eventarc/alpha/channel.yaml new file mode 100755 index 000000000..8d6aad05e --- /dev/null +++ b/services/google/eventarc/alpha/channel.yaml @@ -0,0 +1,162 @@ +# Copyright 2022 Google LLC. All Rights Reserved. +# +# 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. +info: + title: Eventarc/Channel + description: The Eventarc Channel resource + x-dcl-struct-name: Channel + x-dcl-has-iam: false +paths: + get: + description: The function used to get information about a Channel + parameters: + - name: Channel + required: true + description: A full instance of a Channel + apply: + description: The function used to apply information about a Channel + parameters: + - name: Channel + required: true + description: A full instance of a Channel + delete: + description: The function used to delete a Channel + parameters: + - name: Channel + required: true + description: A full instance of a Channel + deleteAll: + description: The function used to delete all Channel + parameters: + - name: project + required: true + schema: + type: string + - name: location + required: true + schema: + type: string + list: + description: The function used to list information about many Channel + parameters: + - name: project + required: true + schema: + type: string + - name: location + required: true + schema: + type: string +components: + schemas: + Channel: + title: Channel + x-dcl-id: projects/{{project}}/locations/{{location}}/channels/{{name}} + x-dcl-parent-container: project + x-dcl-has-create: true + x-dcl-has-iam: false + x-dcl-read-timeout: 0 + x-dcl-apply-timeout: 0 + x-dcl-delete-timeout: 0 + type: object + required: + - name + - project + - location + properties: + activationToken: + type: string + x-dcl-go-name: ActivationToken + readOnly: true + description: Output only. The activation token for the channel. The token + must be used by the provider to register the channel for publishing. + x-kubernetes-immutable: true + createTime: + type: string + format: date-time + x-dcl-go-name: CreateTime + readOnly: true + description: Output only. The creation time. + x-kubernetes-immutable: true + cryptoKeyName: + type: string + x-dcl-go-name: CryptoKeyName + description: Optional. Resource name of a KMS crypto key (managed by the + user) used to encrypt/decrypt their event data. It must match the pattern + `projects/*/locations/*/keyRings/*/cryptoKeys/*`. + x-dcl-references: + - resource: Cloudkms/CryptoKey + field: selfLink + location: + type: string + x-dcl-go-name: Location + description: The location for the resource + x-kubernetes-immutable: true + name: + type: string + x-dcl-go-name: Name + description: Required. The resource name of the channel. Must be unique + within the location on the project and must be in `projects/{project}/locations/{location}/channels/{channel_id}` + format. + x-kubernetes-immutable: true + project: + type: string + x-dcl-go-name: Project + description: The project for the resource + x-kubernetes-immutable: true + x-dcl-references: + - resource: Cloudresourcemanager/Project + field: name + parent: true + provider: + type: string + x-dcl-go-name: Provider + description: 'The name of the event provider (e.g. Eventarc SaaS partner) + associated with the channel. This provider will be granted permissions + to publish events to the channel. Format: `projects/{project}/locations/{location}/providers/{provider_id}`.' + x-kubernetes-immutable: true + pubsubTopic: + type: string + x-dcl-go-name: PubsubTopic + readOnly: true + description: 'Output only. The name of the Pub/Sub topic created and managed + by Eventarc system as a transport for the event delivery. Format: `projects/{project}/topics/{topic_id}`.' + x-kubernetes-immutable: true + state: + type: string + x-dcl-go-name: State + x-dcl-go-type: ChannelStateEnum + readOnly: true + description: 'Output only. The state of a Channel. Possible values: STATE_UNSPECIFIED, + PENDING, ACTIVE, INACTIVE' + x-kubernetes-immutable: true + enum: + - STATE_UNSPECIFIED + - PENDING + - ACTIVE + - INACTIVE + uid: + type: string + x-dcl-go-name: Uid + readOnly: true + description: Output only. Server assigned unique identifier for the channel. + The value is a UUID4 string and guaranteed to remain unchanged until the + resource is deleted. + x-kubernetes-immutable: true + updateTime: + type: string + format: date-time + x-dcl-go-name: UpdateTime + readOnly: true + description: Output only. The last-modified time. + x-kubernetes-immutable: true diff --git a/services/google/eventarc/alpha/channel_alpha_yaml_embed.go b/services/google/eventarc/alpha/channel_alpha_yaml_embed.go new file mode 100755 index 000000000..864d13653 --- /dev/null +++ b/services/google/eventarc/alpha/channel_alpha_yaml_embed.go @@ -0,0 +1,23 @@ +// Copyright 2022 Google LLC. All Rights Reserved. +// +// 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. +// GENERATED BY gen_go_data.go +// gen_go_data -package alpha -var YAML_channel blaze-out/k8-fastbuild/genfiles/cloud/graphite/mmv2/services/google/eventarc/alpha/channel.yaml + +package alpha + +// blaze-out/k8-fastbuild/genfiles/cloud/graphite/mmv2/services/google/eventarc/alpha/channel.yaml +var YAML_channel = []byte("info:\n title: Eventarc/Channel\n description: The Eventarc Channel resource\n x-dcl-struct-name: Channel\n x-dcl-has-iam: false\npaths:\n get:\n description: The function used to get information about a Channel\n parameters:\n - name: Channel\n required: true\n description: A full instance of a Channel\n apply:\n description: The function used to apply information about a Channel\n parameters:\n - name: Channel\n required: true\n description: A full instance of a Channel\n delete:\n description: The function used to delete a Channel\n parameters:\n - name: Channel\n required: true\n description: A full instance of a Channel\n deleteAll:\n description: The function used to delete all Channel\n parameters:\n - name: project\n required: true\n schema:\n type: string\n - name: location\n required: true\n schema:\n type: string\n list:\n description: The function used to list information about many Channel\n parameters:\n - name: project\n required: true\n schema:\n type: string\n - name: location\n required: true\n schema:\n type: string\ncomponents:\n schemas:\n Channel:\n title: Channel\n x-dcl-id: projects/{{project}}/locations/{{location}}/channels/{{name}}\n x-dcl-parent-container: project\n x-dcl-has-create: true\n x-dcl-has-iam: false\n x-dcl-read-timeout: 0\n x-dcl-apply-timeout: 0\n x-dcl-delete-timeout: 0\n type: object\n required:\n - name\n - project\n - location\n properties:\n activationToken:\n type: string\n x-dcl-go-name: ActivationToken\n readOnly: true\n description: Output only. The activation token for the channel. The token\n must be used by the provider to register the channel for publishing.\n x-kubernetes-immutable: true\n createTime:\n type: string\n format: date-time\n x-dcl-go-name: CreateTime\n readOnly: true\n description: Output only. The creation time.\n x-kubernetes-immutable: true\n cryptoKeyName:\n type: string\n x-dcl-go-name: CryptoKeyName\n description: Optional. Resource name of a KMS crypto key (managed by the\n user) used to encrypt/decrypt their event data. It must match the pattern\n `projects/*/locations/*/keyRings/*/cryptoKeys/*`.\n x-dcl-references:\n - resource: Cloudkms/CryptoKey\n field: selfLink\n location:\n type: string\n x-dcl-go-name: Location\n description: The location for the resource\n x-kubernetes-immutable: true\n name:\n type: string\n x-dcl-go-name: Name\n description: Required. The resource name of the channel. Must be unique\n within the location on the project and must be in `projects/{project}/locations/{location}/channels/{channel_id}`\n format.\n x-kubernetes-immutable: true\n project:\n type: string\n x-dcl-go-name: Project\n description: The project for the resource\n x-kubernetes-immutable: true\n x-dcl-references:\n - resource: Cloudresourcemanager/Project\n field: name\n parent: true\n provider:\n type: string\n x-dcl-go-name: Provider\n description: 'The name of the event provider (e.g. Eventarc SaaS partner)\n associated with the channel. This provider will be granted permissions\n to publish events to the channel. Format: `projects/{project}/locations/{location}/providers/{provider_id}`.'\n x-kubernetes-immutable: true\n pubsubTopic:\n type: string\n x-dcl-go-name: PubsubTopic\n readOnly: true\n description: 'Output only. The name of the Pub/Sub topic created and managed\n by Eventarc system as a transport for the event delivery. Format: `projects/{project}/topics/{topic_id}`.'\n x-kubernetes-immutable: true\n state:\n type: string\n x-dcl-go-name: State\n x-dcl-go-type: ChannelStateEnum\n readOnly: true\n description: 'Output only. The state of a Channel. Possible values: STATE_UNSPECIFIED,\n PENDING, ACTIVE, INACTIVE'\n x-kubernetes-immutable: true\n enum:\n - STATE_UNSPECIFIED\n - PENDING\n - ACTIVE\n - INACTIVE\n uid:\n type: string\n x-dcl-go-name: Uid\n readOnly: true\n description: Output only. Server assigned unique identifier for the channel.\n The value is a UUID4 string and guaranteed to remain unchanged until the\n resource is deleted.\n x-kubernetes-immutable: true\n updateTime:\n type: string\n format: date-time\n x-dcl-go-name: UpdateTime\n readOnly: true\n description: Output only. The last-modified time.\n x-kubernetes-immutable: true\n") + +// 5065 bytes +// MD5: 3c9ef5d33aaeccf49e297775a3ddc3ac diff --git a/services/google/eventarc/alpha/channel_internal.go b/services/google/eventarc/alpha/channel_internal.go new file mode 100755 index 000000000..e8a2dd52e --- /dev/null +++ b/services/google/eventarc/alpha/channel_internal.go @@ -0,0 +1,901 @@ +// Copyright 2022 Google LLC. All Rights Reserved. +// +// 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 alpha + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io/ioutil" + "strings" + + "github.com/GoogleCloudPlatform/declarative-resource-client-library/dcl" + "github.com/GoogleCloudPlatform/declarative-resource-client-library/dcl/operations" +) + +func (r *Channel) validate() error { + + if err := dcl.Required(r, "name"); err != nil { + return err + } + if err := dcl.RequiredParameter(r.Project, "Project"); err != nil { + return err + } + if err := dcl.RequiredParameter(r.Location, "Location"); err != nil { + return err + } + return nil +} +func (r *Channel) basePath() string { + params := map[string]interface{}{} + return dcl.Nprintf("https://eventarc.googleapis.com/v1/", params) +} + +func (r *Channel) getURL(userBasePath string) (string, error) { + nr := r.urlNormalized() + params := map[string]interface{}{ + "project": dcl.ValueOrEmptyString(nr.Project), + "location": dcl.ValueOrEmptyString(nr.Location), + "name": dcl.ValueOrEmptyString(nr.Name), + } + return dcl.URL("projects/{{project}}/locations/{{location}}/channels/{{name}}", nr.basePath(), userBasePath, params), nil +} + +func (r *Channel) listURL(userBasePath string) (string, error) { + nr := r.urlNormalized() + params := map[string]interface{}{ + "project": dcl.ValueOrEmptyString(nr.Project), + "location": dcl.ValueOrEmptyString(nr.Location), + } + return dcl.URL("projects/{{project}}/locations/{{location}}/channels", nr.basePath(), userBasePath, params), nil + +} + +func (r *Channel) createURL(userBasePath string) (string, error) { + nr := r.urlNormalized() + params := map[string]interface{}{ + "project": dcl.ValueOrEmptyString(nr.Project), + "location": dcl.ValueOrEmptyString(nr.Location), + "name": dcl.ValueOrEmptyString(nr.Name), + } + return dcl.URL("projects/{{project}}/locations/{{location}}/channels?channelId={{name}}", nr.basePath(), userBasePath, params), nil + +} + +func (r *Channel) deleteURL(userBasePath string) (string, error) { + nr := r.urlNormalized() + params := map[string]interface{}{ + "project": dcl.ValueOrEmptyString(nr.Project), + "location": dcl.ValueOrEmptyString(nr.Location), + "name": dcl.ValueOrEmptyString(nr.Name), + } + return dcl.URL("projects/{{project}}/locations/{{location}}/channels/{{name}}", nr.basePath(), userBasePath, params), nil +} + +// channelApiOperation represents a mutable operation in the underlying REST +// API such as Create, Update, or Delete. +type channelApiOperation interface { + do(context.Context, *Channel, *Client) error +} + +// newUpdateChannelUpdateChannelRequest creates a request for an +// Channel resource's UpdateChannel update type by filling in the update +// fields based on the intended state of the resource. +func newUpdateChannelUpdateChannelRequest(ctx context.Context, f *Channel, c *Client) (map[string]interface{}, error) { + req := map[string]interface{}{} + res := f + _ = res + + if v := f.CryptoKeyName; !dcl.IsEmptyValueIndirect(v) { + req["cryptoKeyName"] = v + } + req["name"] = fmt.Sprintf("projects/%s/locations/%s/channels/%s", *f.Project, *f.Location, *f.Name) + + return req, nil +} + +// marshalUpdateChannelUpdateChannelRequest converts the update into +// the final JSON request body. +func marshalUpdateChannelUpdateChannelRequest(c *Client, m map[string]interface{}) ([]byte, error) { + + return json.Marshal(m) +} + +type updateChannelUpdateChannelOperation struct { + // If the update operation has the REQUIRES_APPLY_OPTIONS trait, this will be populated. + // Usually it will be nil - this is to prevent us from accidentally depending on apply + // options, which should usually be unnecessary. + ApplyOptions []dcl.ApplyOption + FieldDiffs []*dcl.FieldDiff +} + +// do creates a request and sends it to the appropriate URL. In most operations, +// do will transcribe a subset of the resource into a request object and send a +// PUT request to a single URL. + +func (op *updateChannelUpdateChannelOperation) do(ctx context.Context, r *Channel, c *Client) error { + _, err := c.GetChannel(ctx, r) + if err != nil { + return err + } + + u, err := r.updateURL(c.Config.BasePath, "UpdateChannel") + if err != nil { + return err + } + mask := dcl.UpdateMask(op.FieldDiffs) + u, err = dcl.AddQueryParams(u, map[string]string{"updateMask": mask}) + if err != nil { + return err + } + + req, err := newUpdateChannelUpdateChannelRequest(ctx, r, c) + if err != nil { + return err + } + + c.Config.Logger.InfoWithContextf(ctx, "Created update: %#v", req) + body, err := marshalUpdateChannelUpdateChannelRequest(c, req) + if err != nil { + return err + } + resp, err := dcl.SendRequest(ctx, c.Config, "PATCH", u, bytes.NewBuffer(body), c.Config.RetryProvider) + if err != nil { + return err + } + + var o operations.StandardGCPOperation + if err := dcl.ParseResponse(resp.Response, &o); err != nil { + return err + } + err = o.Wait(context.WithValue(ctx, dcl.DoNotLogRequestsKey, true), c.Config, r.basePath(), "GET") + + if err != nil { + return err + } + + return nil +} + +func (c *Client) listChannelRaw(ctx context.Context, r *Channel, pageToken string, pageSize int32) ([]byte, error) { + u, err := r.urlNormalized().listURL(c.Config.BasePath) + if err != nil { + return nil, err + } + + m := make(map[string]string) + if pageToken != "" { + m["pageToken"] = pageToken + } + + if pageSize != ChannelMaxPage { + m["pageSize"] = fmt.Sprintf("%v", pageSize) + } + + u, err = dcl.AddQueryParams(u, m) + if err != nil { + return nil, err + } + resp, err := dcl.SendRequest(ctx, c.Config, "GET", u, &bytes.Buffer{}, c.Config.RetryProvider) + if err != nil { + return nil, err + } + defer resp.Response.Body.Close() + return ioutil.ReadAll(resp.Response.Body) +} + +type listChannelOperation struct { + Channels []map[string]interface{} `json:"channels"` + Token string `json:"nextPageToken"` +} + +func (c *Client) listChannel(ctx context.Context, r *Channel, pageToken string, pageSize int32) ([]*Channel, string, error) { + b, err := c.listChannelRaw(ctx, r, pageToken, pageSize) + if err != nil { + return nil, "", err + } + + var m listChannelOperation + if err := json.Unmarshal(b, &m); err != nil { + return nil, "", err + } + + var l []*Channel + for _, v := range m.Channels { + res, err := unmarshalMapChannel(v, c, r) + if err != nil { + return nil, m.Token, err + } + res.Project = r.Project + res.Location = r.Location + l = append(l, res) + } + + return l, m.Token, nil +} + +func (c *Client) deleteAllChannel(ctx context.Context, f func(*Channel) bool, resources []*Channel) error { + var errors []string + for _, res := range resources { + if f(res) { + // We do not want deleteAll to fail on a deletion or else it will stop deleting other resources. + err := c.DeleteChannel(ctx, res) + if err != nil { + errors = append(errors, err.Error()) + } + } + } + if len(errors) > 0 { + return fmt.Errorf("%v", strings.Join(errors, "\n")) + } else { + return nil + } +} + +type deleteChannelOperation struct{} + +func (op *deleteChannelOperation) do(ctx context.Context, r *Channel, c *Client) error { + r, err := c.GetChannel(ctx, r) + if err != nil { + if dcl.IsNotFound(err) { + c.Config.Logger.InfoWithContextf(ctx, "Channel not found, returning. Original error: %v", err) + return nil + } + c.Config.Logger.WarningWithContextf(ctx, "GetChannel checking for existence. error: %v", err) + return err + } + + u, err := r.deleteURL(c.Config.BasePath) + if err != nil { + return err + } + + // Delete should never have a body + body := &bytes.Buffer{} + resp, err := dcl.SendRequest(ctx, c.Config, "DELETE", u, body, c.Config.RetryProvider) + if err != nil { + return err + } + + // wait for object to be deleted. + var o operations.StandardGCPOperation + if err := dcl.ParseResponse(resp.Response, &o); err != nil { + return err + } + if err := o.Wait(context.WithValue(ctx, dcl.DoNotLogRequestsKey, true), c.Config, r.basePath(), "GET"); err != nil { + return err + } + + // We saw a race condition where for some successful delete operation, the Get calls returned resources for a short duration. + // This is the reason we are adding retry to handle that case. + retriesRemaining := 10 + dcl.Do(ctx, func(ctx context.Context) (*dcl.RetryDetails, error) { + _, err := c.GetChannel(ctx, r) + if dcl.IsNotFound(err) { + return nil, nil + } + if retriesRemaining > 0 { + retriesRemaining-- + return &dcl.RetryDetails{}, dcl.OperationNotDone{} + } + return nil, dcl.NotDeletedError{ExistingResource: r} + }, c.Config.RetryProvider) + return nil +} + +// Create operations are similar to Update operations, although they do not have +// specific request objects. The Create request object is the json encoding of +// the resource, which is modified by res.marshal to form the base request body. +type createChannelOperation struct { + response map[string]interface{} +} + +func (op *createChannelOperation) FirstResponse() (map[string]interface{}, bool) { + return op.response, len(op.response) > 0 +} + +func (op *createChannelOperation) do(ctx context.Context, r *Channel, c *Client) error { + c.Config.Logger.InfoWithContextf(ctx, "Attempting to create %v", r) + u, err := r.createURL(c.Config.BasePath) + if err != nil { + return err + } + + req, err := r.marshal(c) + if err != nil { + return err + } + resp, err := dcl.SendRequest(ctx, c.Config, "POST", u, bytes.NewBuffer(req), c.Config.RetryProvider) + if err != nil { + return err + } + // wait for object to be created. + var o operations.StandardGCPOperation + if err := dcl.ParseResponse(resp.Response, &o); err != nil { + return err + } + if err := o.Wait(context.WithValue(ctx, dcl.DoNotLogRequestsKey, true), c.Config, r.basePath(), "GET"); err != nil { + c.Config.Logger.Warningf("Creation failed after waiting for operation: %v", err) + return err + } + c.Config.Logger.InfoWithContextf(ctx, "Successfully waited for operation") + op.response, _ = o.FirstResponse() + + if _, err := c.GetChannel(ctx, r); err != nil { + c.Config.Logger.WarningWithContextf(ctx, "get returned error: %v", err) + return err + } + + return nil +} + +func (c *Client) getChannelRaw(ctx context.Context, r *Channel) ([]byte, error) { + + u, err := r.getURL(c.Config.BasePath) + if err != nil { + return nil, err + } + resp, err := dcl.SendRequest(ctx, c.Config, "GET", u, &bytes.Buffer{}, c.Config.RetryProvider) + if err != nil { + return nil, err + } + defer resp.Response.Body.Close() + b, err := ioutil.ReadAll(resp.Response.Body) + if err != nil { + return nil, err + } + + return b, nil +} + +func (c *Client) channelDiffsForRawDesired(ctx context.Context, rawDesired *Channel, opts ...dcl.ApplyOption) (initial, desired *Channel, diffs []*dcl.FieldDiff, err error) { + c.Config.Logger.InfoWithContext(ctx, "Fetching initial state...") + // First, let us see if the user provided a state hint. If they did, we will start fetching based on that. + var fetchState *Channel + if sh := dcl.FetchStateHint(opts); sh != nil { + if r, ok := sh.(*Channel); !ok { + c.Config.Logger.WarningWithContextf(ctx, "Initial state hint was of the wrong type; expected Channel, got %T", sh) + } else { + fetchState = r + } + } + if fetchState == nil { + fetchState = rawDesired + } + + // 1.2: Retrieval of raw initial state from API + rawInitial, err := c.GetChannel(ctx, fetchState) + if rawInitial == nil { + if !dcl.IsNotFound(err) { + c.Config.Logger.WarningWithContextf(ctx, "Failed to retrieve whether a Channel resource already exists: %s", err) + return nil, nil, nil, fmt.Errorf("failed to retrieve Channel resource: %v", err) + } + c.Config.Logger.InfoWithContext(ctx, "Found that Channel resource did not exist.") + // Perform canonicalization to pick up defaults. + desired, err = canonicalizeChannelDesiredState(rawDesired, rawInitial) + return nil, desired, nil, err + } + c.Config.Logger.InfoWithContextf(ctx, "Found initial state for Channel: %v", rawInitial) + c.Config.Logger.InfoWithContextf(ctx, "Initial desired state for Channel: %v", rawDesired) + + // The Get call applies postReadExtract and so the result may contain fields that are not part of API version. + if err := extractChannelFields(rawInitial); err != nil { + return nil, nil, nil, err + } + + // 1.3: Canonicalize raw initial state into initial state. + initial, err = canonicalizeChannelInitialState(rawInitial, rawDesired) + if err != nil { + return nil, nil, nil, err + } + c.Config.Logger.InfoWithContextf(ctx, "Canonicalized initial state for Channel: %v", initial) + + // 1.4: Canonicalize raw desired state into desired state. + desired, err = canonicalizeChannelDesiredState(rawDesired, rawInitial, opts...) + if err != nil { + return nil, nil, nil, err + } + c.Config.Logger.InfoWithContextf(ctx, "Canonicalized desired state for Channel: %v", desired) + + // 2.1: Comparison of initial and desired state. + diffs, err = diffChannel(c, desired, initial, opts...) + return initial, desired, diffs, err +} + +func canonicalizeChannelInitialState(rawInitial, rawDesired *Channel) (*Channel, error) { + // TODO(magic-modules-eng): write canonicalizer once relevant traits are added. + return rawInitial, nil +} + +/* +* Canonicalizers +* +* These are responsible for converting either a user-specified config or a +* GCP API response to a standard format that can be used for difference checking. +* */ + +func canonicalizeChannelDesiredState(rawDesired, rawInitial *Channel, opts ...dcl.ApplyOption) (*Channel, error) { + + if rawInitial == nil { + // Since the initial state is empty, the desired state is all we have. + // We canonicalize the remaining nested objects with nil to pick up defaults. + + return rawDesired, nil + } + canonicalDesired := &Channel{} + if dcl.PartialSelfLinkToSelfLink(rawDesired.Name, rawInitial.Name) { + canonicalDesired.Name = rawInitial.Name + } else { + canonicalDesired.Name = rawDesired.Name + } + if dcl.StringCanonicalize(rawDesired.Provider, rawInitial.Provider) { + canonicalDesired.Provider = rawInitial.Provider + } else { + canonicalDesired.Provider = rawDesired.Provider + } + if dcl.IsZeroValue(rawDesired.CryptoKeyName) || (dcl.IsEmptyValueIndirect(rawDesired.CryptoKeyName) && dcl.IsEmptyValueIndirect(rawInitial.CryptoKeyName)) { + // Desired and initial values are equivalent, so set canonical desired value to initial value. + canonicalDesired.CryptoKeyName = rawInitial.CryptoKeyName + } else { + canonicalDesired.CryptoKeyName = rawDesired.CryptoKeyName + } + if dcl.NameToSelfLink(rawDesired.Project, rawInitial.Project) { + canonicalDesired.Project = rawInitial.Project + } else { + canonicalDesired.Project = rawDesired.Project + } + if dcl.NameToSelfLink(rawDesired.Location, rawInitial.Location) { + canonicalDesired.Location = rawInitial.Location + } else { + canonicalDesired.Location = rawDesired.Location + } + + return canonicalDesired, nil +} + +func canonicalizeChannelNewState(c *Client, rawNew, rawDesired *Channel) (*Channel, error) { + + if dcl.IsEmptyValueIndirect(rawNew.Name) && dcl.IsEmptyValueIndirect(rawDesired.Name) { + rawNew.Name = rawDesired.Name + } else { + if dcl.PartialSelfLinkToSelfLink(rawDesired.Name, rawNew.Name) { + rawNew.Name = rawDesired.Name + } + } + + if dcl.IsEmptyValueIndirect(rawNew.Uid) && dcl.IsEmptyValueIndirect(rawDesired.Uid) { + rawNew.Uid = rawDesired.Uid + } else { + if dcl.StringCanonicalize(rawDesired.Uid, rawNew.Uid) { + rawNew.Uid = rawDesired.Uid + } + } + + if dcl.IsEmptyValueIndirect(rawNew.CreateTime) && dcl.IsEmptyValueIndirect(rawDesired.CreateTime) { + rawNew.CreateTime = rawDesired.CreateTime + } else { + } + + if dcl.IsEmptyValueIndirect(rawNew.UpdateTime) && dcl.IsEmptyValueIndirect(rawDesired.UpdateTime) { + rawNew.UpdateTime = rawDesired.UpdateTime + } else { + } + + if dcl.IsEmptyValueIndirect(rawNew.Provider) && dcl.IsEmptyValueIndirect(rawDesired.Provider) { + rawNew.Provider = rawDesired.Provider + } else { + if dcl.StringCanonicalize(rawDesired.Provider, rawNew.Provider) { + rawNew.Provider = rawDesired.Provider + } + } + + if dcl.IsEmptyValueIndirect(rawNew.PubsubTopic) && dcl.IsEmptyValueIndirect(rawDesired.PubsubTopic) { + rawNew.PubsubTopic = rawDesired.PubsubTopic + } else { + if dcl.StringCanonicalize(rawDesired.PubsubTopic, rawNew.PubsubTopic) { + rawNew.PubsubTopic = rawDesired.PubsubTopic + } + } + + if dcl.IsEmptyValueIndirect(rawNew.State) && dcl.IsEmptyValueIndirect(rawDesired.State) { + rawNew.State = rawDesired.State + } else { + } + + if dcl.IsEmptyValueIndirect(rawNew.ActivationToken) && dcl.IsEmptyValueIndirect(rawDesired.ActivationToken) { + rawNew.ActivationToken = rawDesired.ActivationToken + } else { + if dcl.StringCanonicalize(rawDesired.ActivationToken, rawNew.ActivationToken) { + rawNew.ActivationToken = rawDesired.ActivationToken + } + } + + if dcl.IsEmptyValueIndirect(rawNew.CryptoKeyName) && dcl.IsEmptyValueIndirect(rawDesired.CryptoKeyName) { + rawNew.CryptoKeyName = rawDesired.CryptoKeyName + } else { + } + + rawNew.Project = rawDesired.Project + + rawNew.Location = rawDesired.Location + + return rawNew, nil +} + +// The differ returns a list of diffs, along with a list of operations that should be taken +// to remedy them. Right now, it does not attempt to consolidate operations - if several +// fields can be fixed with a patch update, it will perform the patch several times. +// Diffs on some fields will be ignored if the `desired` state has an empty (nil) +// value. This empty value indicates that the user does not care about the state for +// the field. Empty fields on the actual object will cause diffs. +// TODO(magic-modules-eng): for efficiency in some resources, add batching. +func diffChannel(c *Client, desired, actual *Channel, opts ...dcl.ApplyOption) ([]*dcl.FieldDiff, error) { + if desired == nil || actual == nil { + return nil, fmt.Errorf("nil resource passed to diff - always a programming error: %#v, %#v", desired, actual) + } + + c.Config.Logger.Infof("Diff function called with desired state: %v", desired) + c.Config.Logger.Infof("Diff function called with actual state: %v", actual) + + var fn dcl.FieldName + var newDiffs []*dcl.FieldDiff + // New style diffs. + if ds, err := dcl.Diff(desired.Name, actual.Name, dcl.DiffInfo{OperationSelector: dcl.RequiresRecreate()}, fn.AddNest("Name")); len(ds) != 0 || err != nil { + if err != nil { + return nil, err + } + newDiffs = append(newDiffs, ds...) + } + + if ds, err := dcl.Diff(desired.Uid, actual.Uid, dcl.DiffInfo{OutputOnly: true, OperationSelector: dcl.RequiresRecreate()}, fn.AddNest("Uid")); len(ds) != 0 || err != nil { + if err != nil { + return nil, err + } + newDiffs = append(newDiffs, ds...) + } + + if ds, err := dcl.Diff(desired.CreateTime, actual.CreateTime, dcl.DiffInfo{OutputOnly: true, OperationSelector: dcl.RequiresRecreate()}, fn.AddNest("CreateTime")); len(ds) != 0 || err != nil { + if err != nil { + return nil, err + } + newDiffs = append(newDiffs, ds...) + } + + if ds, err := dcl.Diff(desired.UpdateTime, actual.UpdateTime, dcl.DiffInfo{OutputOnly: true, OperationSelector: dcl.RequiresRecreate()}, fn.AddNest("UpdateTime")); len(ds) != 0 || err != nil { + if err != nil { + return nil, err + } + newDiffs = append(newDiffs, ds...) + } + + if ds, err := dcl.Diff(desired.Provider, actual.Provider, dcl.DiffInfo{OperationSelector: dcl.RequiresRecreate()}, fn.AddNest("Provider")); len(ds) != 0 || err != nil { + if err != nil { + return nil, err + } + newDiffs = append(newDiffs, ds...) + } + + if ds, err := dcl.Diff(desired.PubsubTopic, actual.PubsubTopic, dcl.DiffInfo{OutputOnly: true, OperationSelector: dcl.RequiresRecreate()}, fn.AddNest("PubsubTopic")); len(ds) != 0 || err != nil { + if err != nil { + return nil, err + } + newDiffs = append(newDiffs, ds...) + } + + if ds, err := dcl.Diff(desired.State, actual.State, dcl.DiffInfo{OutputOnly: true, Type: "EnumType", OperationSelector: dcl.RequiresRecreate()}, fn.AddNest("State")); len(ds) != 0 || err != nil { + if err != nil { + return nil, err + } + newDiffs = append(newDiffs, ds...) + } + + if ds, err := dcl.Diff(desired.ActivationToken, actual.ActivationToken, dcl.DiffInfo{OutputOnly: true, OperationSelector: dcl.RequiresRecreate()}, fn.AddNest("ActivationToken")); len(ds) != 0 || err != nil { + if err != nil { + return nil, err + } + newDiffs = append(newDiffs, ds...) + } + + if ds, err := dcl.Diff(desired.CryptoKeyName, actual.CryptoKeyName, dcl.DiffInfo{Type: "ReferenceType", OperationSelector: dcl.TriggersOperation("updateChannelUpdateChannelOperation")}, fn.AddNest("CryptoKeyName")); len(ds) != 0 || err != nil { + if err != nil { + return nil, err + } + newDiffs = append(newDiffs, ds...) + } + + if ds, err := dcl.Diff(desired.Project, actual.Project, dcl.DiffInfo{Type: "ReferenceType", OperationSelector: dcl.RequiresRecreate()}, fn.AddNest("Project")); len(ds) != 0 || err != nil { + if err != nil { + return nil, err + } + newDiffs = append(newDiffs, ds...) + } + + if ds, err := dcl.Diff(desired.Location, actual.Location, dcl.DiffInfo{OperationSelector: dcl.RequiresRecreate()}, fn.AddNest("Location")); len(ds) != 0 || err != nil { + if err != nil { + return nil, err + } + newDiffs = append(newDiffs, ds...) + } + + return newDiffs, nil +} + +// urlNormalized returns a copy of the resource struct with values normalized +// for URL substitutions. For instance, it converts long-form self-links to +// short-form so they can be substituted in. +func (r *Channel) urlNormalized() *Channel { + normalized := dcl.Copy(*r).(Channel) + normalized.Name = dcl.SelfLinkToName(r.Name) + normalized.Uid = dcl.SelfLinkToName(r.Uid) + normalized.Provider = dcl.SelfLinkToName(r.Provider) + normalized.PubsubTopic = dcl.SelfLinkToName(r.PubsubTopic) + normalized.ActivationToken = dcl.SelfLinkToName(r.ActivationToken) + normalized.CryptoKeyName = r.CryptoKeyName + normalized.Project = dcl.SelfLinkToName(r.Project) + normalized.Location = dcl.SelfLinkToName(r.Location) + return &normalized +} + +func (r *Channel) updateURL(userBasePath, updateName string) (string, error) { + nr := r.urlNormalized() + if updateName == "UpdateChannel" { + fields := map[string]interface{}{ + "project": dcl.ValueOrEmptyString(nr.Project), + "location": dcl.ValueOrEmptyString(nr.Location), + "name": dcl.ValueOrEmptyString(nr.Name), + } + return dcl.URL("projects/{{project}}/locations/{{location}}/channels/{{name}}", nr.basePath(), userBasePath, fields), nil + + } + + return "", fmt.Errorf("unknown update name: %s", updateName) +} + +// marshal encodes the Channel resource into JSON for a Create request, and +// performs transformations from the resource schema to the API schema if +// necessary. +func (r *Channel) marshal(c *Client) ([]byte, error) { + m, err := expandChannel(c, r) + if err != nil { + return nil, fmt.Errorf("error marshalling Channel: %w", err) + } + + return json.Marshal(m) +} + +// unmarshalChannel decodes JSON responses into the Channel resource schema. +func unmarshalChannel(b []byte, c *Client, res *Channel) (*Channel, error) { + var m map[string]interface{} + if err := json.Unmarshal(b, &m); err != nil { + return nil, err + } + return unmarshalMapChannel(m, c, res) +} + +func unmarshalMapChannel(m map[string]interface{}, c *Client, res *Channel) (*Channel, error) { + + flattened := flattenChannel(c, m, res) + if flattened == nil { + return nil, fmt.Errorf("attempted to flatten empty json object") + } + return flattened, nil +} + +// expandChannel expands Channel into a JSON request object. +func expandChannel(c *Client, f *Channel) (map[string]interface{}, error) { + m := make(map[string]interface{}) + res := f + _ = res + if v, err := dcl.DeriveField("projects/%s/locations/%s/channels/%s", f.Name, dcl.SelfLinkToName(f.Project), dcl.SelfLinkToName(f.Location), dcl.SelfLinkToName(f.Name)); err != nil { + return nil, fmt.Errorf("error expanding Name into name: %w", err) + } else if !dcl.IsEmptyValueIndirect(v) { + m["name"] = v + } + if v := f.Provider; dcl.ValueShouldBeSent(v) { + m["provider"] = v + } + if v := f.CryptoKeyName; dcl.ValueShouldBeSent(v) { + m["cryptoKeyName"] = v + } + if v, err := dcl.EmptyValue(); err != nil { + return nil, fmt.Errorf("error expanding Project into project: %w", err) + } else if !dcl.IsEmptyValueIndirect(v) { + m["project"] = v + } + if v, err := dcl.EmptyValue(); err != nil { + return nil, fmt.Errorf("error expanding Location into location: %w", err) + } else if !dcl.IsEmptyValueIndirect(v) { + m["location"] = v + } + + return m, nil +} + +// flattenChannel flattens Channel from a JSON request object into the +// Channel type. +func flattenChannel(c *Client, i interface{}, res *Channel) *Channel { + m, ok := i.(map[string]interface{}) + if !ok { + return nil + } + if len(m) == 0 { + return nil + } + + resultRes := &Channel{} + resultRes.Name = dcl.FlattenString(m["name"]) + resultRes.Uid = dcl.FlattenString(m["uid"]) + resultRes.CreateTime = dcl.FlattenString(m["createTime"]) + resultRes.UpdateTime = dcl.FlattenString(m["updateTime"]) + resultRes.Provider = dcl.FlattenString(m["provider"]) + resultRes.PubsubTopic = dcl.FlattenString(m["pubsubTopic"]) + resultRes.State = flattenChannelStateEnum(m["state"]) + resultRes.ActivationToken = dcl.FlattenString(m["activationToken"]) + resultRes.CryptoKeyName = dcl.FlattenString(m["cryptoKeyName"]) + resultRes.Project = dcl.FlattenString(m["project"]) + resultRes.Location = dcl.FlattenString(m["location"]) + + return resultRes +} + +// flattenChannelStateEnumMap flattens the contents of ChannelStateEnum from a JSON +// response object. +func flattenChannelStateEnumMap(c *Client, i interface{}, res *Channel) map[string]ChannelStateEnum { + a, ok := i.(map[string]interface{}) + if !ok { + return map[string]ChannelStateEnum{} + } + + if len(a) == 0 { + return map[string]ChannelStateEnum{} + } + + items := make(map[string]ChannelStateEnum) + for k, item := range a { + items[k] = *flattenChannelStateEnum(item.(interface{})) + } + + return items +} + +// flattenChannelStateEnumSlice flattens the contents of ChannelStateEnum from a JSON +// response object. +func flattenChannelStateEnumSlice(c *Client, i interface{}, res *Channel) []ChannelStateEnum { + a, ok := i.([]interface{}) + if !ok { + return []ChannelStateEnum{} + } + + if len(a) == 0 { + return []ChannelStateEnum{} + } + + items := make([]ChannelStateEnum, 0, len(a)) + for _, item := range a { + items = append(items, *flattenChannelStateEnum(item.(interface{}))) + } + + return items +} + +// flattenChannelStateEnum asserts that an interface is a string, and returns a +// pointer to a *ChannelStateEnum with the same value as that string. +func flattenChannelStateEnum(i interface{}) *ChannelStateEnum { + s, ok := i.(string) + if !ok { + return nil + } + + return ChannelStateEnumRef(s) +} + +// This function returns a matcher that checks whether a serialized resource matches this resource +// in its parameters (as defined by the fields in a Get, which definitionally define resource +// identity). This is useful in extracting the element from a List call. +func (r *Channel) matcher(c *Client) func([]byte) bool { + return func(b []byte) bool { + cr, err := unmarshalChannel(b, c, r) + if err != nil { + c.Config.Logger.Warning("failed to unmarshal provided resource in matcher.") + return false + } + nr := r.urlNormalized() + ncr := cr.urlNormalized() + c.Config.Logger.Infof("looking for %v\nin %v", nr, ncr) + + if nr.Project == nil && ncr.Project == nil { + c.Config.Logger.Info("Both Project fields null - considering equal.") + } else if nr.Project == nil || ncr.Project == nil { + c.Config.Logger.Info("Only one Project field is null - considering unequal.") + return false + } else if *nr.Project != *ncr.Project { + return false + } + if nr.Location == nil && ncr.Location == nil { + c.Config.Logger.Info("Both Location fields null - considering equal.") + } else if nr.Location == nil || ncr.Location == nil { + c.Config.Logger.Info("Only one Location field is null - considering unequal.") + return false + } else if *nr.Location != *ncr.Location { + return false + } + if nr.Name == nil && ncr.Name == nil { + c.Config.Logger.Info("Both Name fields null - considering equal.") + } else if nr.Name == nil || ncr.Name == nil { + c.Config.Logger.Info("Only one Name field is null - considering unequal.") + return false + } else if *nr.Name != *ncr.Name { + return false + } + return true + } +} + +type channelDiff struct { + // The diff should include one or the other of RequiresRecreate or UpdateOp. + RequiresRecreate bool + UpdateOp channelApiOperation +} + +func convertFieldDiffsToChannelDiffs(config *dcl.Config, fds []*dcl.FieldDiff, opts []dcl.ApplyOption) ([]channelDiff, error) { + opNamesToFieldDiffs := make(map[string][]*dcl.FieldDiff) + // Map each operation name to the field diffs associated with it. + for _, fd := range fds { + for _, ro := range fd.ResultingOperation { + if fieldDiffs, ok := opNamesToFieldDiffs[ro]; ok { + fieldDiffs = append(fieldDiffs, fd) + opNamesToFieldDiffs[ro] = fieldDiffs + } else { + config.Logger.Infof("%s required due to diff: %v", ro, fd) + opNamesToFieldDiffs[ro] = []*dcl.FieldDiff{fd} + } + } + } + var diffs []channelDiff + // For each operation name, create a channelDiff which contains the operation. + for opName, fieldDiffs := range opNamesToFieldDiffs { + diff := channelDiff{} + if opName == "Recreate" { + diff.RequiresRecreate = true + } else { + apiOp, err := convertOpNameToChannelApiOperation(opName, fieldDiffs, opts...) + if err != nil { + return diffs, err + } + diff.UpdateOp = apiOp + } + diffs = append(diffs, diff) + } + return diffs, nil +} + +func convertOpNameToChannelApiOperation(opName string, fieldDiffs []*dcl.FieldDiff, opts ...dcl.ApplyOption) (channelApiOperation, error) { + switch opName { + + case "updateChannelUpdateChannelOperation": + return &updateChannelUpdateChannelOperation{FieldDiffs: fieldDiffs}, nil + + default: + return nil, fmt.Errorf("no such operation with name: %v", opName) + } +} + +func extractChannelFields(r *Channel) error { + return nil +} + +func postReadExtractChannelFields(r *Channel) error { + return nil +} diff --git a/services/google/eventarc/alpha/channel_schema.go b/services/google/eventarc/alpha/channel_schema.go new file mode 100755 index 000000000..d7474a806 --- /dev/null +++ b/services/google/eventarc/alpha/channel_schema.go @@ -0,0 +1,211 @@ +// Copyright 2022 Google LLC. All Rights Reserved. +// +// 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 alpha + +import ( + "github.com/GoogleCloudPlatform/declarative-resource-client-library/dcl" +) + +func DCLChannelSchema() *dcl.Schema { + return &dcl.Schema{ + Info: &dcl.Info{ + Title: "Eventarc/Channel", + Description: "The Eventarc Channel resource", + StructName: "Channel", + }, + Paths: &dcl.Paths{ + Get: &dcl.Path{ + Description: "The function used to get information about a Channel", + Parameters: []dcl.PathParameters{ + dcl.PathParameters{ + Name: "Channel", + Required: true, + Description: "A full instance of a Channel", + }, + }, + }, + Apply: &dcl.Path{ + Description: "The function used to apply information about a Channel", + Parameters: []dcl.PathParameters{ + dcl.PathParameters{ + Name: "Channel", + Required: true, + Description: "A full instance of a Channel", + }, + }, + }, + Delete: &dcl.Path{ + Description: "The function used to delete a Channel", + Parameters: []dcl.PathParameters{ + dcl.PathParameters{ + Name: "Channel", + Required: true, + Description: "A full instance of a Channel", + }, + }, + }, + DeleteAll: &dcl.Path{ + Description: "The function used to delete all Channel", + Parameters: []dcl.PathParameters{ + dcl.PathParameters{ + Name: "project", + Required: true, + Schema: &dcl.PathParametersSchema{ + Type: "string", + }, + }, + dcl.PathParameters{ + Name: "location", + Required: true, + Schema: &dcl.PathParametersSchema{ + Type: "string", + }, + }, + }, + }, + List: &dcl.Path{ + Description: "The function used to list information about many Channel", + Parameters: []dcl.PathParameters{ + dcl.PathParameters{ + Name: "project", + Required: true, + Schema: &dcl.PathParametersSchema{ + Type: "string", + }, + }, + dcl.PathParameters{ + Name: "location", + Required: true, + Schema: &dcl.PathParametersSchema{ + Type: "string", + }, + }, + }, + }, + }, + Components: &dcl.Components{ + Schemas: map[string]*dcl.Component{ + "Channel": &dcl.Component{ + Title: "Channel", + ID: "projects/{{project}}/locations/{{location}}/channels/{{name}}", + ParentContainer: "project", + HasCreate: true, + SchemaProperty: dcl.Property{ + Type: "object", + Required: []string{ + "name", + "project", + "location", + }, + Properties: map[string]*dcl.Property{ + "activationToken": &dcl.Property{ + Type: "string", + GoName: "ActivationToken", + ReadOnly: true, + Description: "Output only. The activation token for the channel. The token must be used by the provider to register the channel for publishing.", + Immutable: true, + }, + "createTime": &dcl.Property{ + Type: "string", + Format: "date-time", + GoName: "CreateTime", + ReadOnly: true, + Description: "Output only. The creation time.", + Immutable: true, + }, + "cryptoKeyName": &dcl.Property{ + Type: "string", + GoName: "CryptoKeyName", + Description: "Optional. Resource name of a KMS crypto key (managed by the user) used to encrypt/decrypt their event data. It must match the pattern `projects/*/locations/*/keyRings/*/cryptoKeys/*`.", + ResourceReferences: []*dcl.PropertyResourceReference{ + &dcl.PropertyResourceReference{ + Resource: "Cloudkms/CryptoKey", + Field: "selfLink", + }, + }, + }, + "location": &dcl.Property{ + Type: "string", + GoName: "Location", + Description: "The location for the resource", + Immutable: true, + }, + "name": &dcl.Property{ + Type: "string", + GoName: "Name", + Description: "Required. The resource name of the channel. Must be unique within the location on the project and must be in `projects/{project}/locations/{location}/channels/{channel_id}` format.", + Immutable: true, + }, + "project": &dcl.Property{ + Type: "string", + GoName: "Project", + Description: "The project for the resource", + Immutable: true, + ResourceReferences: []*dcl.PropertyResourceReference{ + &dcl.PropertyResourceReference{ + Resource: "Cloudresourcemanager/Project", + Field: "name", + Parent: true, + }, + }, + }, + "provider": &dcl.Property{ + Type: "string", + GoName: "Provider", + Description: "The name of the event provider (e.g. Eventarc SaaS partner) associated with the channel. This provider will be granted permissions to publish events to the channel. Format: `projects/{project}/locations/{location}/providers/{provider_id}`.", + Immutable: true, + }, + "pubsubTopic": &dcl.Property{ + Type: "string", + GoName: "PubsubTopic", + ReadOnly: true, + Description: "Output only. The name of the Pub/Sub topic created and managed by Eventarc system as a transport for the event delivery. Format: `projects/{project}/topics/{topic_id}`.", + Immutable: true, + }, + "state": &dcl.Property{ + Type: "string", + GoName: "State", + GoType: "ChannelStateEnum", + ReadOnly: true, + Description: "Output only. The state of a Channel. Possible values: STATE_UNSPECIFIED, PENDING, ACTIVE, INACTIVE", + Immutable: true, + Enum: []string{ + "STATE_UNSPECIFIED", + "PENDING", + "ACTIVE", + "INACTIVE", + }, + }, + "uid": &dcl.Property{ + Type: "string", + GoName: "Uid", + ReadOnly: true, + Description: "Output only. Server assigned unique identifier for the channel. The value is a UUID4 string and guaranteed to remain unchanged until the resource is deleted.", + Immutable: true, + }, + "updateTime": &dcl.Property{ + Type: "string", + Format: "date-time", + GoName: "UpdateTime", + ReadOnly: true, + Description: "Output only. The last-modified time.", + Immutable: true, + }, + }, + }, + }, + }, + }, + } +} diff --git a/services/google/eventarc/beta/channel.go b/services/google/eventarc/beta/channel.go new file mode 100755 index 000000000..6163a0c99 --- /dev/null +++ b/services/google/eventarc/beta/channel.go @@ -0,0 +1,436 @@ +// Copyright 2022 Google LLC. All Rights Reserved. +// +// 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 beta + +import ( + "context" + "fmt" + "time" + + "google.golang.org/api/googleapi" + "github.com/GoogleCloudPlatform/declarative-resource-client-library/dcl" +) + +type Channel struct { + Name *string `json:"name"` + Uid *string `json:"uid"` + CreateTime *string `json:"createTime"` + UpdateTime *string `json:"updateTime"` + Provider *string `json:"provider"` + PubsubTopic *string `json:"pubsubTopic"` + State *ChannelStateEnum `json:"state"` + ActivationToken *string `json:"activationToken"` + CryptoKeyName *string `json:"cryptoKeyName"` + Project *string `json:"project"` + Location *string `json:"location"` +} + +func (r *Channel) String() string { + return dcl.SprintResource(r) +} + +// The enum ChannelStateEnum. +type ChannelStateEnum string + +// ChannelStateEnumRef returns a *ChannelStateEnum with the value of string s +// If the empty string is provided, nil is returned. +func ChannelStateEnumRef(s string) *ChannelStateEnum { + v := ChannelStateEnum(s) + return &v +} + +func (v ChannelStateEnum) Validate() error { + if string(v) == "" { + // Empty enum is okay. + return nil + } + for _, s := range []string{"STATE_UNSPECIFIED", "PENDING", "ACTIVE", "INACTIVE"} { + if string(v) == s { + return nil + } + } + return &dcl.EnumInvalidError{ + Enum: "ChannelStateEnum", + Value: string(v), + Valid: []string{}, + } +} + +// Describe returns a simple description of this resource to ensure that automated tools +// can identify it. +func (r *Channel) Describe() dcl.ServiceTypeVersion { + return dcl.ServiceTypeVersion{ + Service: "eventarc", + Type: "Channel", + Version: "beta", + } +} + +func (r *Channel) ID() (string, error) { + if err := extractChannelFields(r); err != nil { + return "", err + } + nr := r.urlNormalized() + params := map[string]interface{}{ + "name": dcl.ValueOrEmptyString(nr.Name), + "uid": dcl.ValueOrEmptyString(nr.Uid), + "create_time": dcl.ValueOrEmptyString(nr.CreateTime), + "update_time": dcl.ValueOrEmptyString(nr.UpdateTime), + "provider": dcl.ValueOrEmptyString(nr.Provider), + "pubsub_topic": dcl.ValueOrEmptyString(nr.PubsubTopic), + "state": dcl.ValueOrEmptyString(nr.State), + "activation_token": dcl.ValueOrEmptyString(nr.ActivationToken), + "crypto_key_name": dcl.ValueOrEmptyString(nr.CryptoKeyName), + "project": dcl.ValueOrEmptyString(nr.Project), + "location": dcl.ValueOrEmptyString(nr.Location), + } + return dcl.Nprintf("projects/{{project}}/locations/{{location}}/channels/{{name}}", params), nil +} + +const ChannelMaxPage = -1 + +type ChannelList struct { + Items []*Channel + + nextToken string + + pageSize int32 + + resource *Channel +} + +func (l *ChannelList) HasNext() bool { + return l.nextToken != "" +} + +func (l *ChannelList) Next(ctx context.Context, c *Client) error { + ctx, cancel := context.WithTimeout(ctx, c.Config.TimeoutOr(0*time.Second)) + defer cancel() + + if !l.HasNext() { + return fmt.Errorf("no next page") + } + items, token, err := c.listChannel(ctx, l.resource, l.nextToken, l.pageSize) + if err != nil { + return err + } + l.Items = items + l.nextToken = token + return err +} + +func (c *Client) ListChannel(ctx context.Context, project, location string) (*ChannelList, error) { + ctx = dcl.ContextWithRequestID(ctx) + c = NewClient(c.Config.Clone(dcl.WithCodeRetryability(map[int]dcl.Retryability{ + 403: dcl.Retryability{ + Retryable: true, + Pattern: "", + Timeout: 10000000000, + }, + }))) + ctx, cancel := context.WithTimeout(ctx, c.Config.TimeoutOr(0*time.Second)) + defer cancel() + + return c.ListChannelWithMaxResults(ctx, project, location, ChannelMaxPage) + +} + +func (c *Client) ListChannelWithMaxResults(ctx context.Context, project, location string, pageSize int32) (*ChannelList, error) { + ctx, cancel := context.WithTimeout(ctx, c.Config.TimeoutOr(0*time.Second)) + defer cancel() + + // Create a resource object so that we can use proper url normalization methods. + r := &Channel{ + Project: &project, + Location: &location, + } + items, token, err := c.listChannel(ctx, r, "", pageSize) + if err != nil { + return nil, err + } + return &ChannelList{ + Items: items, + nextToken: token, + pageSize: pageSize, + resource: r, + }, nil +} + +func (c *Client) GetChannel(ctx context.Context, r *Channel) (*Channel, error) { + ctx = dcl.ContextWithRequestID(ctx) + c = NewClient(c.Config.Clone(dcl.WithCodeRetryability(map[int]dcl.Retryability{ + 403: dcl.Retryability{ + Retryable: true, + Pattern: "", + Timeout: 10000000000, + }, + }))) + ctx, cancel := context.WithTimeout(ctx, c.Config.TimeoutOr(0*time.Second)) + defer cancel() + + // This is *purposefully* supressing errors. + // This function is used with url-normalized values + not URL normalized values. + // URL Normalized values will throw unintentional errors, since those values are not of the proper parent form. + extractChannelFields(r) + + b, err := c.getChannelRaw(ctx, r) + if err != nil { + if dcl.IsNotFound(err) { + return nil, &googleapi.Error{ + Code: 404, + Message: err.Error(), + } + } + return nil, err + } + result, err := unmarshalChannel(b, c, r) + if err != nil { + return nil, err + } + result.Project = r.Project + result.Location = r.Location + result.Name = r.Name + + c.Config.Logger.InfoWithContextf(ctx, "Retrieved raw result state: %v", result) + c.Config.Logger.InfoWithContextf(ctx, "Canonicalizing with specified state: %v", r) + result, err = canonicalizeChannelNewState(c, result, r) + if err != nil { + return nil, err + } + if err := postReadExtractChannelFields(result); err != nil { + return result, err + } + c.Config.Logger.InfoWithContextf(ctx, "Created result state: %v", result) + + return result, nil +} + +func (c *Client) DeleteChannel(ctx context.Context, r *Channel) error { + ctx = dcl.ContextWithRequestID(ctx) + c = NewClient(c.Config.Clone(dcl.WithCodeRetryability(map[int]dcl.Retryability{ + 403: dcl.Retryability{ + Retryable: true, + Pattern: "", + Timeout: 10000000000, + }, + }))) + ctx, cancel := context.WithTimeout(ctx, c.Config.TimeoutOr(0*time.Second)) + defer cancel() + + if r == nil { + return fmt.Errorf("Channel resource is nil") + } + c.Config.Logger.InfoWithContext(ctx, "Deleting Channel...") + deleteOp := deleteChannelOperation{} + return deleteOp.do(ctx, r, c) +} + +// DeleteAllChannel deletes all resources that the filter functions returns true on. +func (c *Client) DeleteAllChannel(ctx context.Context, project, location string, filter func(*Channel) bool) error { + listObj, err := c.ListChannel(ctx, project, location) + if err != nil { + return err + } + + err = c.deleteAllChannel(ctx, filter, listObj.Items) + if err != nil { + return err + } + for listObj.HasNext() { + err = listObj.Next(ctx, c) + if err != nil { + return nil + } + err = c.deleteAllChannel(ctx, filter, listObj.Items) + if err != nil { + return err + } + } + return nil +} + +func (c *Client) ApplyChannel(ctx context.Context, rawDesired *Channel, opts ...dcl.ApplyOption) (*Channel, error) { + ctx, cancel := context.WithTimeout(ctx, c.Config.TimeoutOr(0*time.Second)) + defer cancel() + + ctx = dcl.ContextWithRequestID(ctx) + c = NewClient(c.Config.Clone(dcl.WithCodeRetryability(map[int]dcl.Retryability{ + 403: dcl.Retryability{ + Retryable: true, + Pattern: "", + Timeout: 10000000000, + }, + }))) + var resultNewState *Channel + err := dcl.Do(ctx, func(ctx context.Context) (*dcl.RetryDetails, error) { + newState, err := applyChannelHelper(c, ctx, rawDesired, opts...) + resultNewState = newState + if err != nil { + // If the error is 409, there is conflict in resource update. + // Here we want to apply changes based on latest state. + if dcl.IsConflictError(err) { + return &dcl.RetryDetails{}, dcl.OperationNotDone{Err: err} + } + return nil, err + } + return nil, nil + }, c.Config.RetryProvider) + return resultNewState, err +} + +func applyChannelHelper(c *Client, ctx context.Context, rawDesired *Channel, opts ...dcl.ApplyOption) (*Channel, error) { + c.Config.Logger.InfoWithContext(ctx, "Beginning ApplyChannel...") + c.Config.Logger.InfoWithContextf(ctx, "User specified desired state: %v", rawDesired) + + // 1.1: Validation of user-specified fields in desired state. + if err := rawDesired.validate(); err != nil { + return nil, err + } + + if err := extractChannelFields(rawDesired); err != nil { + return nil, err + } + + initial, desired, fieldDiffs, err := c.channelDiffsForRawDesired(ctx, rawDesired, opts...) + if err != nil { + return nil, fmt.Errorf("failed to create a diff: %w", err) + } + + diffs, err := convertFieldDiffsToChannelDiffs(c.Config, fieldDiffs, opts) + if err != nil { + return nil, err + } + + // TODO(magic-modules-eng): 2.2 Feasibility check (all updates are feasible so far). + + // 2.3: Lifecycle Directive Check + var create bool + lp := dcl.FetchLifecycleParams(opts) + if initial == nil { + if dcl.HasLifecycleParam(lp, dcl.BlockCreation) { + return nil, dcl.ApplyInfeasibleError{Message: fmt.Sprintf("Creation blocked by lifecycle params: %#v.", desired)} + } + create = true + } else if dcl.HasLifecycleParam(lp, dcl.BlockAcquire) { + return nil, dcl.ApplyInfeasibleError{ + Message: fmt.Sprintf("Resource already exists - apply blocked by lifecycle params: %#v.", initial), + } + } else { + for _, d := range diffs { + if d.RequiresRecreate { + return nil, dcl.ApplyInfeasibleError{ + Message: fmt.Sprintf("infeasible update: (%v) would require recreation", d), + } + } + if dcl.HasLifecycleParam(lp, dcl.BlockModification) { + return nil, dcl.ApplyInfeasibleError{Message: fmt.Sprintf("Modification blocked, diff (%v) unresolvable.", d)} + } + } + } + + // 2.4 Imperative Request Planning + var ops []channelApiOperation + if create { + ops = append(ops, &createChannelOperation{}) + } else { + for _, d := range diffs { + ops = append(ops, d.UpdateOp) + } + } + c.Config.Logger.InfoWithContextf(ctx, "Created plan: %#v", ops) + + // 2.5 Request Actuation + for _, op := range ops { + c.Config.Logger.InfoWithContextf(ctx, "Performing operation %T %+v", op, op) + if err := op.do(ctx, desired, c); err != nil { + c.Config.Logger.InfoWithContextf(ctx, "Failed operation %T %+v: %v", op, op, err) + return nil, err + } + c.Config.Logger.InfoWithContextf(ctx, "Finished operation %T %+v", op, op) + } + return applyChannelDiff(c, ctx, desired, rawDesired, ops, opts...) +} + +func applyChannelDiff(c *Client, ctx context.Context, desired *Channel, rawDesired *Channel, ops []channelApiOperation, opts ...dcl.ApplyOption) (*Channel, error) { + // 3.1, 3.2a Retrieval of raw new state & canonicalization with desired state + c.Config.Logger.InfoWithContext(ctx, "Retrieving raw new state...") + rawNew, err := c.GetChannel(ctx, desired) + if err != nil { + return nil, err + } + // Get additional values from the first response. + // These values should be merged into the newState above. + if len(ops) > 0 { + lastOp := ops[len(ops)-1] + if o, ok := lastOp.(*createChannelOperation); ok { + if r, hasR := o.FirstResponse(); hasR { + + c.Config.Logger.InfoWithContext(ctx, "Retrieving raw new state from operation...") + + fullResp, err := unmarshalMapChannel(r, c, rawDesired) + if err != nil { + return nil, err + } + + rawNew, err = canonicalizeChannelNewState(c, rawNew, fullResp) + if err != nil { + return nil, err + } + } + } + } + + c.Config.Logger.InfoWithContextf(ctx, "Canonicalizing with raw desired state: %v", rawDesired) + // 3.2b Canonicalization of raw new state using raw desired state + newState, err := canonicalizeChannelNewState(c, rawNew, rawDesired) + if err != nil { + return rawNew, err + } + + c.Config.Logger.InfoWithContextf(ctx, "Created canonical new state: %v", newState) + // 3.3 Comparison of the new state and raw desired state. + // TODO(magic-modules-eng): EVENTUALLY_CONSISTENT_UPDATE + newDesired, err := canonicalizeChannelDesiredState(rawDesired, newState) + if err != nil { + return newState, err + } + + if err := postReadExtractChannelFields(newState); err != nil { + return newState, err + } + + // Need to ensure any transformations made here match acceptably in differ. + if err := postReadExtractChannelFields(newDesired); err != nil { + return newState, err + } + + c.Config.Logger.InfoWithContextf(ctx, "Diffing using canonicalized desired state: %v", newDesired) + newDiffs, err := diffChannel(c, newDesired, newState) + if err != nil { + return newState, err + } + + if len(newDiffs) == 0 { + c.Config.Logger.InfoWithContext(ctx, "No diffs found. Apply was successful.") + } else { + c.Config.Logger.InfoWithContextf(ctx, "Found diffs: %v", newDiffs) + diffMessages := make([]string, len(newDiffs)) + for i, d := range newDiffs { + diffMessages[i] = fmt.Sprintf("%v", d) + } + return newState, dcl.DiffAfterApplyError{Diffs: diffMessages} + } + c.Config.Logger.InfoWithContext(ctx, "Done Apply.") + return newState, nil +} diff --git a/services/google/eventarc/beta/channel.yaml b/services/google/eventarc/beta/channel.yaml new file mode 100755 index 000000000..8d6aad05e --- /dev/null +++ b/services/google/eventarc/beta/channel.yaml @@ -0,0 +1,162 @@ +# Copyright 2022 Google LLC. All Rights Reserved. +# +# 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. +info: + title: Eventarc/Channel + description: The Eventarc Channel resource + x-dcl-struct-name: Channel + x-dcl-has-iam: false +paths: + get: + description: The function used to get information about a Channel + parameters: + - name: Channel + required: true + description: A full instance of a Channel + apply: + description: The function used to apply information about a Channel + parameters: + - name: Channel + required: true + description: A full instance of a Channel + delete: + description: The function used to delete a Channel + parameters: + - name: Channel + required: true + description: A full instance of a Channel + deleteAll: + description: The function used to delete all Channel + parameters: + - name: project + required: true + schema: + type: string + - name: location + required: true + schema: + type: string + list: + description: The function used to list information about many Channel + parameters: + - name: project + required: true + schema: + type: string + - name: location + required: true + schema: + type: string +components: + schemas: + Channel: + title: Channel + x-dcl-id: projects/{{project}}/locations/{{location}}/channels/{{name}} + x-dcl-parent-container: project + x-dcl-has-create: true + x-dcl-has-iam: false + x-dcl-read-timeout: 0 + x-dcl-apply-timeout: 0 + x-dcl-delete-timeout: 0 + type: object + required: + - name + - project + - location + properties: + activationToken: + type: string + x-dcl-go-name: ActivationToken + readOnly: true + description: Output only. The activation token for the channel. The token + must be used by the provider to register the channel for publishing. + x-kubernetes-immutable: true + createTime: + type: string + format: date-time + x-dcl-go-name: CreateTime + readOnly: true + description: Output only. The creation time. + x-kubernetes-immutable: true + cryptoKeyName: + type: string + x-dcl-go-name: CryptoKeyName + description: Optional. Resource name of a KMS crypto key (managed by the + user) used to encrypt/decrypt their event data. It must match the pattern + `projects/*/locations/*/keyRings/*/cryptoKeys/*`. + x-dcl-references: + - resource: Cloudkms/CryptoKey + field: selfLink + location: + type: string + x-dcl-go-name: Location + description: The location for the resource + x-kubernetes-immutable: true + name: + type: string + x-dcl-go-name: Name + description: Required. The resource name of the channel. Must be unique + within the location on the project and must be in `projects/{project}/locations/{location}/channels/{channel_id}` + format. + x-kubernetes-immutable: true + project: + type: string + x-dcl-go-name: Project + description: The project for the resource + x-kubernetes-immutable: true + x-dcl-references: + - resource: Cloudresourcemanager/Project + field: name + parent: true + provider: + type: string + x-dcl-go-name: Provider + description: 'The name of the event provider (e.g. Eventarc SaaS partner) + associated with the channel. This provider will be granted permissions + to publish events to the channel. Format: `projects/{project}/locations/{location}/providers/{provider_id}`.' + x-kubernetes-immutable: true + pubsubTopic: + type: string + x-dcl-go-name: PubsubTopic + readOnly: true + description: 'Output only. The name of the Pub/Sub topic created and managed + by Eventarc system as a transport for the event delivery. Format: `projects/{project}/topics/{topic_id}`.' + x-kubernetes-immutable: true + state: + type: string + x-dcl-go-name: State + x-dcl-go-type: ChannelStateEnum + readOnly: true + description: 'Output only. The state of a Channel. Possible values: STATE_UNSPECIFIED, + PENDING, ACTIVE, INACTIVE' + x-kubernetes-immutable: true + enum: + - STATE_UNSPECIFIED + - PENDING + - ACTIVE + - INACTIVE + uid: + type: string + x-dcl-go-name: Uid + readOnly: true + description: Output only. Server assigned unique identifier for the channel. + The value is a UUID4 string and guaranteed to remain unchanged until the + resource is deleted. + x-kubernetes-immutable: true + updateTime: + type: string + format: date-time + x-dcl-go-name: UpdateTime + readOnly: true + description: Output only. The last-modified time. + x-kubernetes-immutable: true diff --git a/services/google/eventarc/beta/channel_beta_yaml_embed.go b/services/google/eventarc/beta/channel_beta_yaml_embed.go new file mode 100755 index 000000000..864326280 --- /dev/null +++ b/services/google/eventarc/beta/channel_beta_yaml_embed.go @@ -0,0 +1,23 @@ +// Copyright 2022 Google LLC. All Rights Reserved. +// +// 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. +// GENERATED BY gen_go_data.go +// gen_go_data -package beta -var YAML_channel blaze-out/k8-fastbuild/genfiles/cloud/graphite/mmv2/services/google/eventarc/beta/channel.yaml + +package beta + +// blaze-out/k8-fastbuild/genfiles/cloud/graphite/mmv2/services/google/eventarc/beta/channel.yaml +var YAML_channel = []byte("info:\n title: Eventarc/Channel\n description: The Eventarc Channel resource\n x-dcl-struct-name: Channel\n x-dcl-has-iam: false\npaths:\n get:\n description: The function used to get information about a Channel\n parameters:\n - name: Channel\n required: true\n description: A full instance of a Channel\n apply:\n description: The function used to apply information about a Channel\n parameters:\n - name: Channel\n required: true\n description: A full instance of a Channel\n delete:\n description: The function used to delete a Channel\n parameters:\n - name: Channel\n required: true\n description: A full instance of a Channel\n deleteAll:\n description: The function used to delete all Channel\n parameters:\n - name: project\n required: true\n schema:\n type: string\n - name: location\n required: true\n schema:\n type: string\n list:\n description: The function used to list information about many Channel\n parameters:\n - name: project\n required: true\n schema:\n type: string\n - name: location\n required: true\n schema:\n type: string\ncomponents:\n schemas:\n Channel:\n title: Channel\n x-dcl-id: projects/{{project}}/locations/{{location}}/channels/{{name}}\n x-dcl-parent-container: project\n x-dcl-has-create: true\n x-dcl-has-iam: false\n x-dcl-read-timeout: 0\n x-dcl-apply-timeout: 0\n x-dcl-delete-timeout: 0\n type: object\n required:\n - name\n - project\n - location\n properties:\n activationToken:\n type: string\n x-dcl-go-name: ActivationToken\n readOnly: true\n description: Output only. The activation token for the channel. The token\n must be used by the provider to register the channel for publishing.\n x-kubernetes-immutable: true\n createTime:\n type: string\n format: date-time\n x-dcl-go-name: CreateTime\n readOnly: true\n description: Output only. The creation time.\n x-kubernetes-immutable: true\n cryptoKeyName:\n type: string\n x-dcl-go-name: CryptoKeyName\n description: Optional. Resource name of a KMS crypto key (managed by the\n user) used to encrypt/decrypt their event data. It must match the pattern\n `projects/*/locations/*/keyRings/*/cryptoKeys/*`.\n x-dcl-references:\n - resource: Cloudkms/CryptoKey\n field: selfLink\n location:\n type: string\n x-dcl-go-name: Location\n description: The location for the resource\n x-kubernetes-immutable: true\n name:\n type: string\n x-dcl-go-name: Name\n description: Required. The resource name of the channel. Must be unique\n within the location on the project and must be in `projects/{project}/locations/{location}/channels/{channel_id}`\n format.\n x-kubernetes-immutable: true\n project:\n type: string\n x-dcl-go-name: Project\n description: The project for the resource\n x-kubernetes-immutable: true\n x-dcl-references:\n - resource: Cloudresourcemanager/Project\n field: name\n parent: true\n provider:\n type: string\n x-dcl-go-name: Provider\n description: 'The name of the event provider (e.g. Eventarc SaaS partner)\n associated with the channel. This provider will be granted permissions\n to publish events to the channel. Format: `projects/{project}/locations/{location}/providers/{provider_id}`.'\n x-kubernetes-immutable: true\n pubsubTopic:\n type: string\n x-dcl-go-name: PubsubTopic\n readOnly: true\n description: 'Output only. The name of the Pub/Sub topic created and managed\n by Eventarc system as a transport for the event delivery. Format: `projects/{project}/topics/{topic_id}`.'\n x-kubernetes-immutable: true\n state:\n type: string\n x-dcl-go-name: State\n x-dcl-go-type: ChannelStateEnum\n readOnly: true\n description: 'Output only. The state of a Channel. Possible values: STATE_UNSPECIFIED,\n PENDING, ACTIVE, INACTIVE'\n x-kubernetes-immutable: true\n enum:\n - STATE_UNSPECIFIED\n - PENDING\n - ACTIVE\n - INACTIVE\n uid:\n type: string\n x-dcl-go-name: Uid\n readOnly: true\n description: Output only. Server assigned unique identifier for the channel.\n The value is a UUID4 string and guaranteed to remain unchanged until the\n resource is deleted.\n x-kubernetes-immutable: true\n updateTime:\n type: string\n format: date-time\n x-dcl-go-name: UpdateTime\n readOnly: true\n description: Output only. The last-modified time.\n x-kubernetes-immutable: true\n") + +// 5065 bytes +// MD5: 3c9ef5d33aaeccf49e297775a3ddc3ac diff --git a/services/google/eventarc/beta/channel_internal.go b/services/google/eventarc/beta/channel_internal.go new file mode 100755 index 000000000..3aee6f0e0 --- /dev/null +++ b/services/google/eventarc/beta/channel_internal.go @@ -0,0 +1,901 @@ +// Copyright 2022 Google LLC. All Rights Reserved. +// +// 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 beta + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io/ioutil" + "strings" + + "github.com/GoogleCloudPlatform/declarative-resource-client-library/dcl" + "github.com/GoogleCloudPlatform/declarative-resource-client-library/dcl/operations" +) + +func (r *Channel) validate() error { + + if err := dcl.Required(r, "name"); err != nil { + return err + } + if err := dcl.RequiredParameter(r.Project, "Project"); err != nil { + return err + } + if err := dcl.RequiredParameter(r.Location, "Location"); err != nil { + return err + } + return nil +} +func (r *Channel) basePath() string { + params := map[string]interface{}{} + return dcl.Nprintf("https://eventarc.googleapis.com/v1/", params) +} + +func (r *Channel) getURL(userBasePath string) (string, error) { + nr := r.urlNormalized() + params := map[string]interface{}{ + "project": dcl.ValueOrEmptyString(nr.Project), + "location": dcl.ValueOrEmptyString(nr.Location), + "name": dcl.ValueOrEmptyString(nr.Name), + } + return dcl.URL("projects/{{project}}/locations/{{location}}/channels/{{name}}", nr.basePath(), userBasePath, params), nil +} + +func (r *Channel) listURL(userBasePath string) (string, error) { + nr := r.urlNormalized() + params := map[string]interface{}{ + "project": dcl.ValueOrEmptyString(nr.Project), + "location": dcl.ValueOrEmptyString(nr.Location), + } + return dcl.URL("projects/{{project}}/locations/{{location}}/channels", nr.basePath(), userBasePath, params), nil + +} + +func (r *Channel) createURL(userBasePath string) (string, error) { + nr := r.urlNormalized() + params := map[string]interface{}{ + "project": dcl.ValueOrEmptyString(nr.Project), + "location": dcl.ValueOrEmptyString(nr.Location), + "name": dcl.ValueOrEmptyString(nr.Name), + } + return dcl.URL("projects/{{project}}/locations/{{location}}/channels?channelId={{name}}", nr.basePath(), userBasePath, params), nil + +} + +func (r *Channel) deleteURL(userBasePath string) (string, error) { + nr := r.urlNormalized() + params := map[string]interface{}{ + "project": dcl.ValueOrEmptyString(nr.Project), + "location": dcl.ValueOrEmptyString(nr.Location), + "name": dcl.ValueOrEmptyString(nr.Name), + } + return dcl.URL("projects/{{project}}/locations/{{location}}/channels/{{name}}", nr.basePath(), userBasePath, params), nil +} + +// channelApiOperation represents a mutable operation in the underlying REST +// API such as Create, Update, or Delete. +type channelApiOperation interface { + do(context.Context, *Channel, *Client) error +} + +// newUpdateChannelUpdateChannelRequest creates a request for an +// Channel resource's UpdateChannel update type by filling in the update +// fields based on the intended state of the resource. +func newUpdateChannelUpdateChannelRequest(ctx context.Context, f *Channel, c *Client) (map[string]interface{}, error) { + req := map[string]interface{}{} + res := f + _ = res + + if v := f.CryptoKeyName; !dcl.IsEmptyValueIndirect(v) { + req["cryptoKeyName"] = v + } + req["name"] = fmt.Sprintf("projects/%s/locations/%s/channels/%s", *f.Project, *f.Location, *f.Name) + + return req, nil +} + +// marshalUpdateChannelUpdateChannelRequest converts the update into +// the final JSON request body. +func marshalUpdateChannelUpdateChannelRequest(c *Client, m map[string]interface{}) ([]byte, error) { + + return json.Marshal(m) +} + +type updateChannelUpdateChannelOperation struct { + // If the update operation has the REQUIRES_APPLY_OPTIONS trait, this will be populated. + // Usually it will be nil - this is to prevent us from accidentally depending on apply + // options, which should usually be unnecessary. + ApplyOptions []dcl.ApplyOption + FieldDiffs []*dcl.FieldDiff +} + +// do creates a request and sends it to the appropriate URL. In most operations, +// do will transcribe a subset of the resource into a request object and send a +// PUT request to a single URL. + +func (op *updateChannelUpdateChannelOperation) do(ctx context.Context, r *Channel, c *Client) error { + _, err := c.GetChannel(ctx, r) + if err != nil { + return err + } + + u, err := r.updateURL(c.Config.BasePath, "UpdateChannel") + if err != nil { + return err + } + mask := dcl.UpdateMask(op.FieldDiffs) + u, err = dcl.AddQueryParams(u, map[string]string{"updateMask": mask}) + if err != nil { + return err + } + + req, err := newUpdateChannelUpdateChannelRequest(ctx, r, c) + if err != nil { + return err + } + + c.Config.Logger.InfoWithContextf(ctx, "Created update: %#v", req) + body, err := marshalUpdateChannelUpdateChannelRequest(c, req) + if err != nil { + return err + } + resp, err := dcl.SendRequest(ctx, c.Config, "PATCH", u, bytes.NewBuffer(body), c.Config.RetryProvider) + if err != nil { + return err + } + + var o operations.StandardGCPOperation + if err := dcl.ParseResponse(resp.Response, &o); err != nil { + return err + } + err = o.Wait(context.WithValue(ctx, dcl.DoNotLogRequestsKey, true), c.Config, r.basePath(), "GET") + + if err != nil { + return err + } + + return nil +} + +func (c *Client) listChannelRaw(ctx context.Context, r *Channel, pageToken string, pageSize int32) ([]byte, error) { + u, err := r.urlNormalized().listURL(c.Config.BasePath) + if err != nil { + return nil, err + } + + m := make(map[string]string) + if pageToken != "" { + m["pageToken"] = pageToken + } + + if pageSize != ChannelMaxPage { + m["pageSize"] = fmt.Sprintf("%v", pageSize) + } + + u, err = dcl.AddQueryParams(u, m) + if err != nil { + return nil, err + } + resp, err := dcl.SendRequest(ctx, c.Config, "GET", u, &bytes.Buffer{}, c.Config.RetryProvider) + if err != nil { + return nil, err + } + defer resp.Response.Body.Close() + return ioutil.ReadAll(resp.Response.Body) +} + +type listChannelOperation struct { + Channels []map[string]interface{} `json:"channels"` + Token string `json:"nextPageToken"` +} + +func (c *Client) listChannel(ctx context.Context, r *Channel, pageToken string, pageSize int32) ([]*Channel, string, error) { + b, err := c.listChannelRaw(ctx, r, pageToken, pageSize) + if err != nil { + return nil, "", err + } + + var m listChannelOperation + if err := json.Unmarshal(b, &m); err != nil { + return nil, "", err + } + + var l []*Channel + for _, v := range m.Channels { + res, err := unmarshalMapChannel(v, c, r) + if err != nil { + return nil, m.Token, err + } + res.Project = r.Project + res.Location = r.Location + l = append(l, res) + } + + return l, m.Token, nil +} + +func (c *Client) deleteAllChannel(ctx context.Context, f func(*Channel) bool, resources []*Channel) error { + var errors []string + for _, res := range resources { + if f(res) { + // We do not want deleteAll to fail on a deletion or else it will stop deleting other resources. + err := c.DeleteChannel(ctx, res) + if err != nil { + errors = append(errors, err.Error()) + } + } + } + if len(errors) > 0 { + return fmt.Errorf("%v", strings.Join(errors, "\n")) + } else { + return nil + } +} + +type deleteChannelOperation struct{} + +func (op *deleteChannelOperation) do(ctx context.Context, r *Channel, c *Client) error { + r, err := c.GetChannel(ctx, r) + if err != nil { + if dcl.IsNotFound(err) { + c.Config.Logger.InfoWithContextf(ctx, "Channel not found, returning. Original error: %v", err) + return nil + } + c.Config.Logger.WarningWithContextf(ctx, "GetChannel checking for existence. error: %v", err) + return err + } + + u, err := r.deleteURL(c.Config.BasePath) + if err != nil { + return err + } + + // Delete should never have a body + body := &bytes.Buffer{} + resp, err := dcl.SendRequest(ctx, c.Config, "DELETE", u, body, c.Config.RetryProvider) + if err != nil { + return err + } + + // wait for object to be deleted. + var o operations.StandardGCPOperation + if err := dcl.ParseResponse(resp.Response, &o); err != nil { + return err + } + if err := o.Wait(context.WithValue(ctx, dcl.DoNotLogRequestsKey, true), c.Config, r.basePath(), "GET"); err != nil { + return err + } + + // We saw a race condition where for some successful delete operation, the Get calls returned resources for a short duration. + // This is the reason we are adding retry to handle that case. + retriesRemaining := 10 + dcl.Do(ctx, func(ctx context.Context) (*dcl.RetryDetails, error) { + _, err := c.GetChannel(ctx, r) + if dcl.IsNotFound(err) { + return nil, nil + } + if retriesRemaining > 0 { + retriesRemaining-- + return &dcl.RetryDetails{}, dcl.OperationNotDone{} + } + return nil, dcl.NotDeletedError{ExistingResource: r} + }, c.Config.RetryProvider) + return nil +} + +// Create operations are similar to Update operations, although they do not have +// specific request objects. The Create request object is the json encoding of +// the resource, which is modified by res.marshal to form the base request body. +type createChannelOperation struct { + response map[string]interface{} +} + +func (op *createChannelOperation) FirstResponse() (map[string]interface{}, bool) { + return op.response, len(op.response) > 0 +} + +func (op *createChannelOperation) do(ctx context.Context, r *Channel, c *Client) error { + c.Config.Logger.InfoWithContextf(ctx, "Attempting to create %v", r) + u, err := r.createURL(c.Config.BasePath) + if err != nil { + return err + } + + req, err := r.marshal(c) + if err != nil { + return err + } + resp, err := dcl.SendRequest(ctx, c.Config, "POST", u, bytes.NewBuffer(req), c.Config.RetryProvider) + if err != nil { + return err + } + // wait for object to be created. + var o operations.StandardGCPOperation + if err := dcl.ParseResponse(resp.Response, &o); err != nil { + return err + } + if err := o.Wait(context.WithValue(ctx, dcl.DoNotLogRequestsKey, true), c.Config, r.basePath(), "GET"); err != nil { + c.Config.Logger.Warningf("Creation failed after waiting for operation: %v", err) + return err + } + c.Config.Logger.InfoWithContextf(ctx, "Successfully waited for operation") + op.response, _ = o.FirstResponse() + + if _, err := c.GetChannel(ctx, r); err != nil { + c.Config.Logger.WarningWithContextf(ctx, "get returned error: %v", err) + return err + } + + return nil +} + +func (c *Client) getChannelRaw(ctx context.Context, r *Channel) ([]byte, error) { + + u, err := r.getURL(c.Config.BasePath) + if err != nil { + return nil, err + } + resp, err := dcl.SendRequest(ctx, c.Config, "GET", u, &bytes.Buffer{}, c.Config.RetryProvider) + if err != nil { + return nil, err + } + defer resp.Response.Body.Close() + b, err := ioutil.ReadAll(resp.Response.Body) + if err != nil { + return nil, err + } + + return b, nil +} + +func (c *Client) channelDiffsForRawDesired(ctx context.Context, rawDesired *Channel, opts ...dcl.ApplyOption) (initial, desired *Channel, diffs []*dcl.FieldDiff, err error) { + c.Config.Logger.InfoWithContext(ctx, "Fetching initial state...") + // First, let us see if the user provided a state hint. If they did, we will start fetching based on that. + var fetchState *Channel + if sh := dcl.FetchStateHint(opts); sh != nil { + if r, ok := sh.(*Channel); !ok { + c.Config.Logger.WarningWithContextf(ctx, "Initial state hint was of the wrong type; expected Channel, got %T", sh) + } else { + fetchState = r + } + } + if fetchState == nil { + fetchState = rawDesired + } + + // 1.2: Retrieval of raw initial state from API + rawInitial, err := c.GetChannel(ctx, fetchState) + if rawInitial == nil { + if !dcl.IsNotFound(err) { + c.Config.Logger.WarningWithContextf(ctx, "Failed to retrieve whether a Channel resource already exists: %s", err) + return nil, nil, nil, fmt.Errorf("failed to retrieve Channel resource: %v", err) + } + c.Config.Logger.InfoWithContext(ctx, "Found that Channel resource did not exist.") + // Perform canonicalization to pick up defaults. + desired, err = canonicalizeChannelDesiredState(rawDesired, rawInitial) + return nil, desired, nil, err + } + c.Config.Logger.InfoWithContextf(ctx, "Found initial state for Channel: %v", rawInitial) + c.Config.Logger.InfoWithContextf(ctx, "Initial desired state for Channel: %v", rawDesired) + + // The Get call applies postReadExtract and so the result may contain fields that are not part of API version. + if err := extractChannelFields(rawInitial); err != nil { + return nil, nil, nil, err + } + + // 1.3: Canonicalize raw initial state into initial state. + initial, err = canonicalizeChannelInitialState(rawInitial, rawDesired) + if err != nil { + return nil, nil, nil, err + } + c.Config.Logger.InfoWithContextf(ctx, "Canonicalized initial state for Channel: %v", initial) + + // 1.4: Canonicalize raw desired state into desired state. + desired, err = canonicalizeChannelDesiredState(rawDesired, rawInitial, opts...) + if err != nil { + return nil, nil, nil, err + } + c.Config.Logger.InfoWithContextf(ctx, "Canonicalized desired state for Channel: %v", desired) + + // 2.1: Comparison of initial and desired state. + diffs, err = diffChannel(c, desired, initial, opts...) + return initial, desired, diffs, err +} + +func canonicalizeChannelInitialState(rawInitial, rawDesired *Channel) (*Channel, error) { + // TODO(magic-modules-eng): write canonicalizer once relevant traits are added. + return rawInitial, nil +} + +/* +* Canonicalizers +* +* These are responsible for converting either a user-specified config or a +* GCP API response to a standard format that can be used for difference checking. +* */ + +func canonicalizeChannelDesiredState(rawDesired, rawInitial *Channel, opts ...dcl.ApplyOption) (*Channel, error) { + + if rawInitial == nil { + // Since the initial state is empty, the desired state is all we have. + // We canonicalize the remaining nested objects with nil to pick up defaults. + + return rawDesired, nil + } + canonicalDesired := &Channel{} + if dcl.PartialSelfLinkToSelfLink(rawDesired.Name, rawInitial.Name) { + canonicalDesired.Name = rawInitial.Name + } else { + canonicalDesired.Name = rawDesired.Name + } + if dcl.StringCanonicalize(rawDesired.Provider, rawInitial.Provider) { + canonicalDesired.Provider = rawInitial.Provider + } else { + canonicalDesired.Provider = rawDesired.Provider + } + if dcl.IsZeroValue(rawDesired.CryptoKeyName) || (dcl.IsEmptyValueIndirect(rawDesired.CryptoKeyName) && dcl.IsEmptyValueIndirect(rawInitial.CryptoKeyName)) { + // Desired and initial values are equivalent, so set canonical desired value to initial value. + canonicalDesired.CryptoKeyName = rawInitial.CryptoKeyName + } else { + canonicalDesired.CryptoKeyName = rawDesired.CryptoKeyName + } + if dcl.NameToSelfLink(rawDesired.Project, rawInitial.Project) { + canonicalDesired.Project = rawInitial.Project + } else { + canonicalDesired.Project = rawDesired.Project + } + if dcl.NameToSelfLink(rawDesired.Location, rawInitial.Location) { + canonicalDesired.Location = rawInitial.Location + } else { + canonicalDesired.Location = rawDesired.Location + } + + return canonicalDesired, nil +} + +func canonicalizeChannelNewState(c *Client, rawNew, rawDesired *Channel) (*Channel, error) { + + if dcl.IsEmptyValueIndirect(rawNew.Name) && dcl.IsEmptyValueIndirect(rawDesired.Name) { + rawNew.Name = rawDesired.Name + } else { + if dcl.PartialSelfLinkToSelfLink(rawDesired.Name, rawNew.Name) { + rawNew.Name = rawDesired.Name + } + } + + if dcl.IsEmptyValueIndirect(rawNew.Uid) && dcl.IsEmptyValueIndirect(rawDesired.Uid) { + rawNew.Uid = rawDesired.Uid + } else { + if dcl.StringCanonicalize(rawDesired.Uid, rawNew.Uid) { + rawNew.Uid = rawDesired.Uid + } + } + + if dcl.IsEmptyValueIndirect(rawNew.CreateTime) && dcl.IsEmptyValueIndirect(rawDesired.CreateTime) { + rawNew.CreateTime = rawDesired.CreateTime + } else { + } + + if dcl.IsEmptyValueIndirect(rawNew.UpdateTime) && dcl.IsEmptyValueIndirect(rawDesired.UpdateTime) { + rawNew.UpdateTime = rawDesired.UpdateTime + } else { + } + + if dcl.IsEmptyValueIndirect(rawNew.Provider) && dcl.IsEmptyValueIndirect(rawDesired.Provider) { + rawNew.Provider = rawDesired.Provider + } else { + if dcl.StringCanonicalize(rawDesired.Provider, rawNew.Provider) { + rawNew.Provider = rawDesired.Provider + } + } + + if dcl.IsEmptyValueIndirect(rawNew.PubsubTopic) && dcl.IsEmptyValueIndirect(rawDesired.PubsubTopic) { + rawNew.PubsubTopic = rawDesired.PubsubTopic + } else { + if dcl.StringCanonicalize(rawDesired.PubsubTopic, rawNew.PubsubTopic) { + rawNew.PubsubTopic = rawDesired.PubsubTopic + } + } + + if dcl.IsEmptyValueIndirect(rawNew.State) && dcl.IsEmptyValueIndirect(rawDesired.State) { + rawNew.State = rawDesired.State + } else { + } + + if dcl.IsEmptyValueIndirect(rawNew.ActivationToken) && dcl.IsEmptyValueIndirect(rawDesired.ActivationToken) { + rawNew.ActivationToken = rawDesired.ActivationToken + } else { + if dcl.StringCanonicalize(rawDesired.ActivationToken, rawNew.ActivationToken) { + rawNew.ActivationToken = rawDesired.ActivationToken + } + } + + if dcl.IsEmptyValueIndirect(rawNew.CryptoKeyName) && dcl.IsEmptyValueIndirect(rawDesired.CryptoKeyName) { + rawNew.CryptoKeyName = rawDesired.CryptoKeyName + } else { + } + + rawNew.Project = rawDesired.Project + + rawNew.Location = rawDesired.Location + + return rawNew, nil +} + +// The differ returns a list of diffs, along with a list of operations that should be taken +// to remedy them. Right now, it does not attempt to consolidate operations - if several +// fields can be fixed with a patch update, it will perform the patch several times. +// Diffs on some fields will be ignored if the `desired` state has an empty (nil) +// value. This empty value indicates that the user does not care about the state for +// the field. Empty fields on the actual object will cause diffs. +// TODO(magic-modules-eng): for efficiency in some resources, add batching. +func diffChannel(c *Client, desired, actual *Channel, opts ...dcl.ApplyOption) ([]*dcl.FieldDiff, error) { + if desired == nil || actual == nil { + return nil, fmt.Errorf("nil resource passed to diff - always a programming error: %#v, %#v", desired, actual) + } + + c.Config.Logger.Infof("Diff function called with desired state: %v", desired) + c.Config.Logger.Infof("Diff function called with actual state: %v", actual) + + var fn dcl.FieldName + var newDiffs []*dcl.FieldDiff + // New style diffs. + if ds, err := dcl.Diff(desired.Name, actual.Name, dcl.DiffInfo{OperationSelector: dcl.RequiresRecreate()}, fn.AddNest("Name")); len(ds) != 0 || err != nil { + if err != nil { + return nil, err + } + newDiffs = append(newDiffs, ds...) + } + + if ds, err := dcl.Diff(desired.Uid, actual.Uid, dcl.DiffInfo{OutputOnly: true, OperationSelector: dcl.RequiresRecreate()}, fn.AddNest("Uid")); len(ds) != 0 || err != nil { + if err != nil { + return nil, err + } + newDiffs = append(newDiffs, ds...) + } + + if ds, err := dcl.Diff(desired.CreateTime, actual.CreateTime, dcl.DiffInfo{OutputOnly: true, OperationSelector: dcl.RequiresRecreate()}, fn.AddNest("CreateTime")); len(ds) != 0 || err != nil { + if err != nil { + return nil, err + } + newDiffs = append(newDiffs, ds...) + } + + if ds, err := dcl.Diff(desired.UpdateTime, actual.UpdateTime, dcl.DiffInfo{OutputOnly: true, OperationSelector: dcl.RequiresRecreate()}, fn.AddNest("UpdateTime")); len(ds) != 0 || err != nil { + if err != nil { + return nil, err + } + newDiffs = append(newDiffs, ds...) + } + + if ds, err := dcl.Diff(desired.Provider, actual.Provider, dcl.DiffInfo{OperationSelector: dcl.RequiresRecreate()}, fn.AddNest("Provider")); len(ds) != 0 || err != nil { + if err != nil { + return nil, err + } + newDiffs = append(newDiffs, ds...) + } + + if ds, err := dcl.Diff(desired.PubsubTopic, actual.PubsubTopic, dcl.DiffInfo{OutputOnly: true, OperationSelector: dcl.RequiresRecreate()}, fn.AddNest("PubsubTopic")); len(ds) != 0 || err != nil { + if err != nil { + return nil, err + } + newDiffs = append(newDiffs, ds...) + } + + if ds, err := dcl.Diff(desired.State, actual.State, dcl.DiffInfo{OutputOnly: true, Type: "EnumType", OperationSelector: dcl.RequiresRecreate()}, fn.AddNest("State")); len(ds) != 0 || err != nil { + if err != nil { + return nil, err + } + newDiffs = append(newDiffs, ds...) + } + + if ds, err := dcl.Diff(desired.ActivationToken, actual.ActivationToken, dcl.DiffInfo{OutputOnly: true, OperationSelector: dcl.RequiresRecreate()}, fn.AddNest("ActivationToken")); len(ds) != 0 || err != nil { + if err != nil { + return nil, err + } + newDiffs = append(newDiffs, ds...) + } + + if ds, err := dcl.Diff(desired.CryptoKeyName, actual.CryptoKeyName, dcl.DiffInfo{Type: "ReferenceType", OperationSelector: dcl.TriggersOperation("updateChannelUpdateChannelOperation")}, fn.AddNest("CryptoKeyName")); len(ds) != 0 || err != nil { + if err != nil { + return nil, err + } + newDiffs = append(newDiffs, ds...) + } + + if ds, err := dcl.Diff(desired.Project, actual.Project, dcl.DiffInfo{Type: "ReferenceType", OperationSelector: dcl.RequiresRecreate()}, fn.AddNest("Project")); len(ds) != 0 || err != nil { + if err != nil { + return nil, err + } + newDiffs = append(newDiffs, ds...) + } + + if ds, err := dcl.Diff(desired.Location, actual.Location, dcl.DiffInfo{OperationSelector: dcl.RequiresRecreate()}, fn.AddNest("Location")); len(ds) != 0 || err != nil { + if err != nil { + return nil, err + } + newDiffs = append(newDiffs, ds...) + } + + return newDiffs, nil +} + +// urlNormalized returns a copy of the resource struct with values normalized +// for URL substitutions. For instance, it converts long-form self-links to +// short-form so they can be substituted in. +func (r *Channel) urlNormalized() *Channel { + normalized := dcl.Copy(*r).(Channel) + normalized.Name = dcl.SelfLinkToName(r.Name) + normalized.Uid = dcl.SelfLinkToName(r.Uid) + normalized.Provider = dcl.SelfLinkToName(r.Provider) + normalized.PubsubTopic = dcl.SelfLinkToName(r.PubsubTopic) + normalized.ActivationToken = dcl.SelfLinkToName(r.ActivationToken) + normalized.CryptoKeyName = r.CryptoKeyName + normalized.Project = dcl.SelfLinkToName(r.Project) + normalized.Location = dcl.SelfLinkToName(r.Location) + return &normalized +} + +func (r *Channel) updateURL(userBasePath, updateName string) (string, error) { + nr := r.urlNormalized() + if updateName == "UpdateChannel" { + fields := map[string]interface{}{ + "project": dcl.ValueOrEmptyString(nr.Project), + "location": dcl.ValueOrEmptyString(nr.Location), + "name": dcl.ValueOrEmptyString(nr.Name), + } + return dcl.URL("projects/{{project}}/locations/{{location}}/channels/{{name}}", nr.basePath(), userBasePath, fields), nil + + } + + return "", fmt.Errorf("unknown update name: %s", updateName) +} + +// marshal encodes the Channel resource into JSON for a Create request, and +// performs transformations from the resource schema to the API schema if +// necessary. +func (r *Channel) marshal(c *Client) ([]byte, error) { + m, err := expandChannel(c, r) + if err != nil { + return nil, fmt.Errorf("error marshalling Channel: %w", err) + } + + return json.Marshal(m) +} + +// unmarshalChannel decodes JSON responses into the Channel resource schema. +func unmarshalChannel(b []byte, c *Client, res *Channel) (*Channel, error) { + var m map[string]interface{} + if err := json.Unmarshal(b, &m); err != nil { + return nil, err + } + return unmarshalMapChannel(m, c, res) +} + +func unmarshalMapChannel(m map[string]interface{}, c *Client, res *Channel) (*Channel, error) { + + flattened := flattenChannel(c, m, res) + if flattened == nil { + return nil, fmt.Errorf("attempted to flatten empty json object") + } + return flattened, nil +} + +// expandChannel expands Channel into a JSON request object. +func expandChannel(c *Client, f *Channel) (map[string]interface{}, error) { + m := make(map[string]interface{}) + res := f + _ = res + if v, err := dcl.DeriveField("projects/%s/locations/%s/channels/%s", f.Name, dcl.SelfLinkToName(f.Project), dcl.SelfLinkToName(f.Location), dcl.SelfLinkToName(f.Name)); err != nil { + return nil, fmt.Errorf("error expanding Name into name: %w", err) + } else if !dcl.IsEmptyValueIndirect(v) { + m["name"] = v + } + if v := f.Provider; dcl.ValueShouldBeSent(v) { + m["provider"] = v + } + if v := f.CryptoKeyName; dcl.ValueShouldBeSent(v) { + m["cryptoKeyName"] = v + } + if v, err := dcl.EmptyValue(); err != nil { + return nil, fmt.Errorf("error expanding Project into project: %w", err) + } else if !dcl.IsEmptyValueIndirect(v) { + m["project"] = v + } + if v, err := dcl.EmptyValue(); err != nil { + return nil, fmt.Errorf("error expanding Location into location: %w", err) + } else if !dcl.IsEmptyValueIndirect(v) { + m["location"] = v + } + + return m, nil +} + +// flattenChannel flattens Channel from a JSON request object into the +// Channel type. +func flattenChannel(c *Client, i interface{}, res *Channel) *Channel { + m, ok := i.(map[string]interface{}) + if !ok { + return nil + } + if len(m) == 0 { + return nil + } + + resultRes := &Channel{} + resultRes.Name = dcl.FlattenString(m["name"]) + resultRes.Uid = dcl.FlattenString(m["uid"]) + resultRes.CreateTime = dcl.FlattenString(m["createTime"]) + resultRes.UpdateTime = dcl.FlattenString(m["updateTime"]) + resultRes.Provider = dcl.FlattenString(m["provider"]) + resultRes.PubsubTopic = dcl.FlattenString(m["pubsubTopic"]) + resultRes.State = flattenChannelStateEnum(m["state"]) + resultRes.ActivationToken = dcl.FlattenString(m["activationToken"]) + resultRes.CryptoKeyName = dcl.FlattenString(m["cryptoKeyName"]) + resultRes.Project = dcl.FlattenString(m["project"]) + resultRes.Location = dcl.FlattenString(m["location"]) + + return resultRes +} + +// flattenChannelStateEnumMap flattens the contents of ChannelStateEnum from a JSON +// response object. +func flattenChannelStateEnumMap(c *Client, i interface{}, res *Channel) map[string]ChannelStateEnum { + a, ok := i.(map[string]interface{}) + if !ok { + return map[string]ChannelStateEnum{} + } + + if len(a) == 0 { + return map[string]ChannelStateEnum{} + } + + items := make(map[string]ChannelStateEnum) + for k, item := range a { + items[k] = *flattenChannelStateEnum(item.(interface{})) + } + + return items +} + +// flattenChannelStateEnumSlice flattens the contents of ChannelStateEnum from a JSON +// response object. +func flattenChannelStateEnumSlice(c *Client, i interface{}, res *Channel) []ChannelStateEnum { + a, ok := i.([]interface{}) + if !ok { + return []ChannelStateEnum{} + } + + if len(a) == 0 { + return []ChannelStateEnum{} + } + + items := make([]ChannelStateEnum, 0, len(a)) + for _, item := range a { + items = append(items, *flattenChannelStateEnum(item.(interface{}))) + } + + return items +} + +// flattenChannelStateEnum asserts that an interface is a string, and returns a +// pointer to a *ChannelStateEnum with the same value as that string. +func flattenChannelStateEnum(i interface{}) *ChannelStateEnum { + s, ok := i.(string) + if !ok { + return nil + } + + return ChannelStateEnumRef(s) +} + +// This function returns a matcher that checks whether a serialized resource matches this resource +// in its parameters (as defined by the fields in a Get, which definitionally define resource +// identity). This is useful in extracting the element from a List call. +func (r *Channel) matcher(c *Client) func([]byte) bool { + return func(b []byte) bool { + cr, err := unmarshalChannel(b, c, r) + if err != nil { + c.Config.Logger.Warning("failed to unmarshal provided resource in matcher.") + return false + } + nr := r.urlNormalized() + ncr := cr.urlNormalized() + c.Config.Logger.Infof("looking for %v\nin %v", nr, ncr) + + if nr.Project == nil && ncr.Project == nil { + c.Config.Logger.Info("Both Project fields null - considering equal.") + } else if nr.Project == nil || ncr.Project == nil { + c.Config.Logger.Info("Only one Project field is null - considering unequal.") + return false + } else if *nr.Project != *ncr.Project { + return false + } + if nr.Location == nil && ncr.Location == nil { + c.Config.Logger.Info("Both Location fields null - considering equal.") + } else if nr.Location == nil || ncr.Location == nil { + c.Config.Logger.Info("Only one Location field is null - considering unequal.") + return false + } else if *nr.Location != *ncr.Location { + return false + } + if nr.Name == nil && ncr.Name == nil { + c.Config.Logger.Info("Both Name fields null - considering equal.") + } else if nr.Name == nil || ncr.Name == nil { + c.Config.Logger.Info("Only one Name field is null - considering unequal.") + return false + } else if *nr.Name != *ncr.Name { + return false + } + return true + } +} + +type channelDiff struct { + // The diff should include one or the other of RequiresRecreate or UpdateOp. + RequiresRecreate bool + UpdateOp channelApiOperation +} + +func convertFieldDiffsToChannelDiffs(config *dcl.Config, fds []*dcl.FieldDiff, opts []dcl.ApplyOption) ([]channelDiff, error) { + opNamesToFieldDiffs := make(map[string][]*dcl.FieldDiff) + // Map each operation name to the field diffs associated with it. + for _, fd := range fds { + for _, ro := range fd.ResultingOperation { + if fieldDiffs, ok := opNamesToFieldDiffs[ro]; ok { + fieldDiffs = append(fieldDiffs, fd) + opNamesToFieldDiffs[ro] = fieldDiffs + } else { + config.Logger.Infof("%s required due to diff: %v", ro, fd) + opNamesToFieldDiffs[ro] = []*dcl.FieldDiff{fd} + } + } + } + var diffs []channelDiff + // For each operation name, create a channelDiff which contains the operation. + for opName, fieldDiffs := range opNamesToFieldDiffs { + diff := channelDiff{} + if opName == "Recreate" { + diff.RequiresRecreate = true + } else { + apiOp, err := convertOpNameToChannelApiOperation(opName, fieldDiffs, opts...) + if err != nil { + return diffs, err + } + diff.UpdateOp = apiOp + } + diffs = append(diffs, diff) + } + return diffs, nil +} + +func convertOpNameToChannelApiOperation(opName string, fieldDiffs []*dcl.FieldDiff, opts ...dcl.ApplyOption) (channelApiOperation, error) { + switch opName { + + case "updateChannelUpdateChannelOperation": + return &updateChannelUpdateChannelOperation{FieldDiffs: fieldDiffs}, nil + + default: + return nil, fmt.Errorf("no such operation with name: %v", opName) + } +} + +func extractChannelFields(r *Channel) error { + return nil +} + +func postReadExtractChannelFields(r *Channel) error { + return nil +} diff --git a/services/google/eventarc/beta/channel_schema.go b/services/google/eventarc/beta/channel_schema.go new file mode 100755 index 000000000..0d9fe1773 --- /dev/null +++ b/services/google/eventarc/beta/channel_schema.go @@ -0,0 +1,211 @@ +// Copyright 2022 Google LLC. All Rights Reserved. +// +// 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 beta + +import ( + "github.com/GoogleCloudPlatform/declarative-resource-client-library/dcl" +) + +func DCLChannelSchema() *dcl.Schema { + return &dcl.Schema{ + Info: &dcl.Info{ + Title: "Eventarc/Channel", + Description: "The Eventarc Channel resource", + StructName: "Channel", + }, + Paths: &dcl.Paths{ + Get: &dcl.Path{ + Description: "The function used to get information about a Channel", + Parameters: []dcl.PathParameters{ + dcl.PathParameters{ + Name: "Channel", + Required: true, + Description: "A full instance of a Channel", + }, + }, + }, + Apply: &dcl.Path{ + Description: "The function used to apply information about a Channel", + Parameters: []dcl.PathParameters{ + dcl.PathParameters{ + Name: "Channel", + Required: true, + Description: "A full instance of a Channel", + }, + }, + }, + Delete: &dcl.Path{ + Description: "The function used to delete a Channel", + Parameters: []dcl.PathParameters{ + dcl.PathParameters{ + Name: "Channel", + Required: true, + Description: "A full instance of a Channel", + }, + }, + }, + DeleteAll: &dcl.Path{ + Description: "The function used to delete all Channel", + Parameters: []dcl.PathParameters{ + dcl.PathParameters{ + Name: "project", + Required: true, + Schema: &dcl.PathParametersSchema{ + Type: "string", + }, + }, + dcl.PathParameters{ + Name: "location", + Required: true, + Schema: &dcl.PathParametersSchema{ + Type: "string", + }, + }, + }, + }, + List: &dcl.Path{ + Description: "The function used to list information about many Channel", + Parameters: []dcl.PathParameters{ + dcl.PathParameters{ + Name: "project", + Required: true, + Schema: &dcl.PathParametersSchema{ + Type: "string", + }, + }, + dcl.PathParameters{ + Name: "location", + Required: true, + Schema: &dcl.PathParametersSchema{ + Type: "string", + }, + }, + }, + }, + }, + Components: &dcl.Components{ + Schemas: map[string]*dcl.Component{ + "Channel": &dcl.Component{ + Title: "Channel", + ID: "projects/{{project}}/locations/{{location}}/channels/{{name}}", + ParentContainer: "project", + HasCreate: true, + SchemaProperty: dcl.Property{ + Type: "object", + Required: []string{ + "name", + "project", + "location", + }, + Properties: map[string]*dcl.Property{ + "activationToken": &dcl.Property{ + Type: "string", + GoName: "ActivationToken", + ReadOnly: true, + Description: "Output only. The activation token for the channel. The token must be used by the provider to register the channel for publishing.", + Immutable: true, + }, + "createTime": &dcl.Property{ + Type: "string", + Format: "date-time", + GoName: "CreateTime", + ReadOnly: true, + Description: "Output only. The creation time.", + Immutable: true, + }, + "cryptoKeyName": &dcl.Property{ + Type: "string", + GoName: "CryptoKeyName", + Description: "Optional. Resource name of a KMS crypto key (managed by the user) used to encrypt/decrypt their event data. It must match the pattern `projects/*/locations/*/keyRings/*/cryptoKeys/*`.", + ResourceReferences: []*dcl.PropertyResourceReference{ + &dcl.PropertyResourceReference{ + Resource: "Cloudkms/CryptoKey", + Field: "selfLink", + }, + }, + }, + "location": &dcl.Property{ + Type: "string", + GoName: "Location", + Description: "The location for the resource", + Immutable: true, + }, + "name": &dcl.Property{ + Type: "string", + GoName: "Name", + Description: "Required. The resource name of the channel. Must be unique within the location on the project and must be in `projects/{project}/locations/{location}/channels/{channel_id}` format.", + Immutable: true, + }, + "project": &dcl.Property{ + Type: "string", + GoName: "Project", + Description: "The project for the resource", + Immutable: true, + ResourceReferences: []*dcl.PropertyResourceReference{ + &dcl.PropertyResourceReference{ + Resource: "Cloudresourcemanager/Project", + Field: "name", + Parent: true, + }, + }, + }, + "provider": &dcl.Property{ + Type: "string", + GoName: "Provider", + Description: "The name of the event provider (e.g. Eventarc SaaS partner) associated with the channel. This provider will be granted permissions to publish events to the channel. Format: `projects/{project}/locations/{location}/providers/{provider_id}`.", + Immutable: true, + }, + "pubsubTopic": &dcl.Property{ + Type: "string", + GoName: "PubsubTopic", + ReadOnly: true, + Description: "Output only. The name of the Pub/Sub topic created and managed by Eventarc system as a transport for the event delivery. Format: `projects/{project}/topics/{topic_id}`.", + Immutable: true, + }, + "state": &dcl.Property{ + Type: "string", + GoName: "State", + GoType: "ChannelStateEnum", + ReadOnly: true, + Description: "Output only. The state of a Channel. Possible values: STATE_UNSPECIFIED, PENDING, ACTIVE, INACTIVE", + Immutable: true, + Enum: []string{ + "STATE_UNSPECIFIED", + "PENDING", + "ACTIVE", + "INACTIVE", + }, + }, + "uid": &dcl.Property{ + Type: "string", + GoName: "Uid", + ReadOnly: true, + Description: "Output only. Server assigned unique identifier for the channel. The value is a UUID4 string and guaranteed to remain unchanged until the resource is deleted.", + Immutable: true, + }, + "updateTime": &dcl.Property{ + Type: "string", + Format: "date-time", + GoName: "UpdateTime", + ReadOnly: true, + Description: "Output only. The last-modified time.", + Immutable: true, + }, + }, + }, + }, + }, + }, + } +} diff --git a/services/google/eventarc/channel.go b/services/google/eventarc/channel.go new file mode 100755 index 000000000..c57be2d01 --- /dev/null +++ b/services/google/eventarc/channel.go @@ -0,0 +1,436 @@ +// Copyright 2022 Google LLC. All Rights Reserved. +// +// 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 eventarc + +import ( + "context" + "fmt" + "time" + + "google.golang.org/api/googleapi" + "github.com/GoogleCloudPlatform/declarative-resource-client-library/dcl" +) + +type Channel struct { + Name *string `json:"name"` + Uid *string `json:"uid"` + CreateTime *string `json:"createTime"` + UpdateTime *string `json:"updateTime"` + Provider *string `json:"provider"` + PubsubTopic *string `json:"pubsubTopic"` + State *ChannelStateEnum `json:"state"` + ActivationToken *string `json:"activationToken"` + CryptoKeyName *string `json:"cryptoKeyName"` + Project *string `json:"project"` + Location *string `json:"location"` +} + +func (r *Channel) String() string { + return dcl.SprintResource(r) +} + +// The enum ChannelStateEnum. +type ChannelStateEnum string + +// ChannelStateEnumRef returns a *ChannelStateEnum with the value of string s +// If the empty string is provided, nil is returned. +func ChannelStateEnumRef(s string) *ChannelStateEnum { + v := ChannelStateEnum(s) + return &v +} + +func (v ChannelStateEnum) Validate() error { + if string(v) == "" { + // Empty enum is okay. + return nil + } + for _, s := range []string{"STATE_UNSPECIFIED", "PENDING", "ACTIVE", "INACTIVE"} { + if string(v) == s { + return nil + } + } + return &dcl.EnumInvalidError{ + Enum: "ChannelStateEnum", + Value: string(v), + Valid: []string{}, + } +} + +// Describe returns a simple description of this resource to ensure that automated tools +// can identify it. +func (r *Channel) Describe() dcl.ServiceTypeVersion { + return dcl.ServiceTypeVersion{ + Service: "eventarc", + Type: "Channel", + Version: "eventarc", + } +} + +func (r *Channel) ID() (string, error) { + if err := extractChannelFields(r); err != nil { + return "", err + } + nr := r.urlNormalized() + params := map[string]interface{}{ + "name": dcl.ValueOrEmptyString(nr.Name), + "uid": dcl.ValueOrEmptyString(nr.Uid), + "create_time": dcl.ValueOrEmptyString(nr.CreateTime), + "update_time": dcl.ValueOrEmptyString(nr.UpdateTime), + "provider": dcl.ValueOrEmptyString(nr.Provider), + "pubsub_topic": dcl.ValueOrEmptyString(nr.PubsubTopic), + "state": dcl.ValueOrEmptyString(nr.State), + "activation_token": dcl.ValueOrEmptyString(nr.ActivationToken), + "crypto_key_name": dcl.ValueOrEmptyString(nr.CryptoKeyName), + "project": dcl.ValueOrEmptyString(nr.Project), + "location": dcl.ValueOrEmptyString(nr.Location), + } + return dcl.Nprintf("projects/{{project}}/locations/{{location}}/channels/{{name}}", params), nil +} + +const ChannelMaxPage = -1 + +type ChannelList struct { + Items []*Channel + + nextToken string + + pageSize int32 + + resource *Channel +} + +func (l *ChannelList) HasNext() bool { + return l.nextToken != "" +} + +func (l *ChannelList) Next(ctx context.Context, c *Client) error { + ctx, cancel := context.WithTimeout(ctx, c.Config.TimeoutOr(0*time.Second)) + defer cancel() + + if !l.HasNext() { + return fmt.Errorf("no next page") + } + items, token, err := c.listChannel(ctx, l.resource, l.nextToken, l.pageSize) + if err != nil { + return err + } + l.Items = items + l.nextToken = token + return err +} + +func (c *Client) ListChannel(ctx context.Context, project, location string) (*ChannelList, error) { + ctx = dcl.ContextWithRequestID(ctx) + c = NewClient(c.Config.Clone(dcl.WithCodeRetryability(map[int]dcl.Retryability{ + 403: dcl.Retryability{ + Retryable: true, + Pattern: "", + Timeout: 10000000000, + }, + }))) + ctx, cancel := context.WithTimeout(ctx, c.Config.TimeoutOr(0*time.Second)) + defer cancel() + + return c.ListChannelWithMaxResults(ctx, project, location, ChannelMaxPage) + +} + +func (c *Client) ListChannelWithMaxResults(ctx context.Context, project, location string, pageSize int32) (*ChannelList, error) { + ctx, cancel := context.WithTimeout(ctx, c.Config.TimeoutOr(0*time.Second)) + defer cancel() + + // Create a resource object so that we can use proper url normalization methods. + r := &Channel{ + Project: &project, + Location: &location, + } + items, token, err := c.listChannel(ctx, r, "", pageSize) + if err != nil { + return nil, err + } + return &ChannelList{ + Items: items, + nextToken: token, + pageSize: pageSize, + resource: r, + }, nil +} + +func (c *Client) GetChannel(ctx context.Context, r *Channel) (*Channel, error) { + ctx = dcl.ContextWithRequestID(ctx) + c = NewClient(c.Config.Clone(dcl.WithCodeRetryability(map[int]dcl.Retryability{ + 403: dcl.Retryability{ + Retryable: true, + Pattern: "", + Timeout: 10000000000, + }, + }))) + ctx, cancel := context.WithTimeout(ctx, c.Config.TimeoutOr(0*time.Second)) + defer cancel() + + // This is *purposefully* supressing errors. + // This function is used with url-normalized values + not URL normalized values. + // URL Normalized values will throw unintentional errors, since those values are not of the proper parent form. + extractChannelFields(r) + + b, err := c.getChannelRaw(ctx, r) + if err != nil { + if dcl.IsNotFound(err) { + return nil, &googleapi.Error{ + Code: 404, + Message: err.Error(), + } + } + return nil, err + } + result, err := unmarshalChannel(b, c, r) + if err != nil { + return nil, err + } + result.Project = r.Project + result.Location = r.Location + result.Name = r.Name + + c.Config.Logger.InfoWithContextf(ctx, "Retrieved raw result state: %v", result) + c.Config.Logger.InfoWithContextf(ctx, "Canonicalizing with specified state: %v", r) + result, err = canonicalizeChannelNewState(c, result, r) + if err != nil { + return nil, err + } + if err := postReadExtractChannelFields(result); err != nil { + return result, err + } + c.Config.Logger.InfoWithContextf(ctx, "Created result state: %v", result) + + return result, nil +} + +func (c *Client) DeleteChannel(ctx context.Context, r *Channel) error { + ctx = dcl.ContextWithRequestID(ctx) + c = NewClient(c.Config.Clone(dcl.WithCodeRetryability(map[int]dcl.Retryability{ + 403: dcl.Retryability{ + Retryable: true, + Pattern: "", + Timeout: 10000000000, + }, + }))) + ctx, cancel := context.WithTimeout(ctx, c.Config.TimeoutOr(0*time.Second)) + defer cancel() + + if r == nil { + return fmt.Errorf("Channel resource is nil") + } + c.Config.Logger.InfoWithContext(ctx, "Deleting Channel...") + deleteOp := deleteChannelOperation{} + return deleteOp.do(ctx, r, c) +} + +// DeleteAllChannel deletes all resources that the filter functions returns true on. +func (c *Client) DeleteAllChannel(ctx context.Context, project, location string, filter func(*Channel) bool) error { + listObj, err := c.ListChannel(ctx, project, location) + if err != nil { + return err + } + + err = c.deleteAllChannel(ctx, filter, listObj.Items) + if err != nil { + return err + } + for listObj.HasNext() { + err = listObj.Next(ctx, c) + if err != nil { + return nil + } + err = c.deleteAllChannel(ctx, filter, listObj.Items) + if err != nil { + return err + } + } + return nil +} + +func (c *Client) ApplyChannel(ctx context.Context, rawDesired *Channel, opts ...dcl.ApplyOption) (*Channel, error) { + ctx, cancel := context.WithTimeout(ctx, c.Config.TimeoutOr(0*time.Second)) + defer cancel() + + ctx = dcl.ContextWithRequestID(ctx) + c = NewClient(c.Config.Clone(dcl.WithCodeRetryability(map[int]dcl.Retryability{ + 403: dcl.Retryability{ + Retryable: true, + Pattern: "", + Timeout: 10000000000, + }, + }))) + var resultNewState *Channel + err := dcl.Do(ctx, func(ctx context.Context) (*dcl.RetryDetails, error) { + newState, err := applyChannelHelper(c, ctx, rawDesired, opts...) + resultNewState = newState + if err != nil { + // If the error is 409, there is conflict in resource update. + // Here we want to apply changes based on latest state. + if dcl.IsConflictError(err) { + return &dcl.RetryDetails{}, dcl.OperationNotDone{Err: err} + } + return nil, err + } + return nil, nil + }, c.Config.RetryProvider) + return resultNewState, err +} + +func applyChannelHelper(c *Client, ctx context.Context, rawDesired *Channel, opts ...dcl.ApplyOption) (*Channel, error) { + c.Config.Logger.InfoWithContext(ctx, "Beginning ApplyChannel...") + c.Config.Logger.InfoWithContextf(ctx, "User specified desired state: %v", rawDesired) + + // 1.1: Validation of user-specified fields in desired state. + if err := rawDesired.validate(); err != nil { + return nil, err + } + + if err := extractChannelFields(rawDesired); err != nil { + return nil, err + } + + initial, desired, fieldDiffs, err := c.channelDiffsForRawDesired(ctx, rawDesired, opts...) + if err != nil { + return nil, fmt.Errorf("failed to create a diff: %w", err) + } + + diffs, err := convertFieldDiffsToChannelDiffs(c.Config, fieldDiffs, opts) + if err != nil { + return nil, err + } + + // TODO(magic-modules-eng): 2.2 Feasibility check (all updates are feasible so far). + + // 2.3: Lifecycle Directive Check + var create bool + lp := dcl.FetchLifecycleParams(opts) + if initial == nil { + if dcl.HasLifecycleParam(lp, dcl.BlockCreation) { + return nil, dcl.ApplyInfeasibleError{Message: fmt.Sprintf("Creation blocked by lifecycle params: %#v.", desired)} + } + create = true + } else if dcl.HasLifecycleParam(lp, dcl.BlockAcquire) { + return nil, dcl.ApplyInfeasibleError{ + Message: fmt.Sprintf("Resource already exists - apply blocked by lifecycle params: %#v.", initial), + } + } else { + for _, d := range diffs { + if d.RequiresRecreate { + return nil, dcl.ApplyInfeasibleError{ + Message: fmt.Sprintf("infeasible update: (%v) would require recreation", d), + } + } + if dcl.HasLifecycleParam(lp, dcl.BlockModification) { + return nil, dcl.ApplyInfeasibleError{Message: fmt.Sprintf("Modification blocked, diff (%v) unresolvable.", d)} + } + } + } + + // 2.4 Imperative Request Planning + var ops []channelApiOperation + if create { + ops = append(ops, &createChannelOperation{}) + } else { + for _, d := range diffs { + ops = append(ops, d.UpdateOp) + } + } + c.Config.Logger.InfoWithContextf(ctx, "Created plan: %#v", ops) + + // 2.5 Request Actuation + for _, op := range ops { + c.Config.Logger.InfoWithContextf(ctx, "Performing operation %T %+v", op, op) + if err := op.do(ctx, desired, c); err != nil { + c.Config.Logger.InfoWithContextf(ctx, "Failed operation %T %+v: %v", op, op, err) + return nil, err + } + c.Config.Logger.InfoWithContextf(ctx, "Finished operation %T %+v", op, op) + } + return applyChannelDiff(c, ctx, desired, rawDesired, ops, opts...) +} + +func applyChannelDiff(c *Client, ctx context.Context, desired *Channel, rawDesired *Channel, ops []channelApiOperation, opts ...dcl.ApplyOption) (*Channel, error) { + // 3.1, 3.2a Retrieval of raw new state & canonicalization with desired state + c.Config.Logger.InfoWithContext(ctx, "Retrieving raw new state...") + rawNew, err := c.GetChannel(ctx, desired) + if err != nil { + return nil, err + } + // Get additional values from the first response. + // These values should be merged into the newState above. + if len(ops) > 0 { + lastOp := ops[len(ops)-1] + if o, ok := lastOp.(*createChannelOperation); ok { + if r, hasR := o.FirstResponse(); hasR { + + c.Config.Logger.InfoWithContext(ctx, "Retrieving raw new state from operation...") + + fullResp, err := unmarshalMapChannel(r, c, rawDesired) + if err != nil { + return nil, err + } + + rawNew, err = canonicalizeChannelNewState(c, rawNew, fullResp) + if err != nil { + return nil, err + } + } + } + } + + c.Config.Logger.InfoWithContextf(ctx, "Canonicalizing with raw desired state: %v", rawDesired) + // 3.2b Canonicalization of raw new state using raw desired state + newState, err := canonicalizeChannelNewState(c, rawNew, rawDesired) + if err != nil { + return rawNew, err + } + + c.Config.Logger.InfoWithContextf(ctx, "Created canonical new state: %v", newState) + // 3.3 Comparison of the new state and raw desired state. + // TODO(magic-modules-eng): EVENTUALLY_CONSISTENT_UPDATE + newDesired, err := canonicalizeChannelDesiredState(rawDesired, newState) + if err != nil { + return newState, err + } + + if err := postReadExtractChannelFields(newState); err != nil { + return newState, err + } + + // Need to ensure any transformations made here match acceptably in differ. + if err := postReadExtractChannelFields(newDesired); err != nil { + return newState, err + } + + c.Config.Logger.InfoWithContextf(ctx, "Diffing using canonicalized desired state: %v", newDesired) + newDiffs, err := diffChannel(c, newDesired, newState) + if err != nil { + return newState, err + } + + if len(newDiffs) == 0 { + c.Config.Logger.InfoWithContext(ctx, "No diffs found. Apply was successful.") + } else { + c.Config.Logger.InfoWithContextf(ctx, "Found diffs: %v", newDiffs) + diffMessages := make([]string, len(newDiffs)) + for i, d := range newDiffs { + diffMessages[i] = fmt.Sprintf("%v", d) + } + return newState, dcl.DiffAfterApplyError{Diffs: diffMessages} + } + c.Config.Logger.InfoWithContext(ctx, "Done Apply.") + return newState, nil +} diff --git a/services/google/eventarc/channel.yaml b/services/google/eventarc/channel.yaml new file mode 100755 index 000000000..8d6aad05e --- /dev/null +++ b/services/google/eventarc/channel.yaml @@ -0,0 +1,162 @@ +# Copyright 2022 Google LLC. All Rights Reserved. +# +# 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. +info: + title: Eventarc/Channel + description: The Eventarc Channel resource + x-dcl-struct-name: Channel + x-dcl-has-iam: false +paths: + get: + description: The function used to get information about a Channel + parameters: + - name: Channel + required: true + description: A full instance of a Channel + apply: + description: The function used to apply information about a Channel + parameters: + - name: Channel + required: true + description: A full instance of a Channel + delete: + description: The function used to delete a Channel + parameters: + - name: Channel + required: true + description: A full instance of a Channel + deleteAll: + description: The function used to delete all Channel + parameters: + - name: project + required: true + schema: + type: string + - name: location + required: true + schema: + type: string + list: + description: The function used to list information about many Channel + parameters: + - name: project + required: true + schema: + type: string + - name: location + required: true + schema: + type: string +components: + schemas: + Channel: + title: Channel + x-dcl-id: projects/{{project}}/locations/{{location}}/channels/{{name}} + x-dcl-parent-container: project + x-dcl-has-create: true + x-dcl-has-iam: false + x-dcl-read-timeout: 0 + x-dcl-apply-timeout: 0 + x-dcl-delete-timeout: 0 + type: object + required: + - name + - project + - location + properties: + activationToken: + type: string + x-dcl-go-name: ActivationToken + readOnly: true + description: Output only. The activation token for the channel. The token + must be used by the provider to register the channel for publishing. + x-kubernetes-immutable: true + createTime: + type: string + format: date-time + x-dcl-go-name: CreateTime + readOnly: true + description: Output only. The creation time. + x-kubernetes-immutable: true + cryptoKeyName: + type: string + x-dcl-go-name: CryptoKeyName + description: Optional. Resource name of a KMS crypto key (managed by the + user) used to encrypt/decrypt their event data. It must match the pattern + `projects/*/locations/*/keyRings/*/cryptoKeys/*`. + x-dcl-references: + - resource: Cloudkms/CryptoKey + field: selfLink + location: + type: string + x-dcl-go-name: Location + description: The location for the resource + x-kubernetes-immutable: true + name: + type: string + x-dcl-go-name: Name + description: Required. The resource name of the channel. Must be unique + within the location on the project and must be in `projects/{project}/locations/{location}/channels/{channel_id}` + format. + x-kubernetes-immutable: true + project: + type: string + x-dcl-go-name: Project + description: The project for the resource + x-kubernetes-immutable: true + x-dcl-references: + - resource: Cloudresourcemanager/Project + field: name + parent: true + provider: + type: string + x-dcl-go-name: Provider + description: 'The name of the event provider (e.g. Eventarc SaaS partner) + associated with the channel. This provider will be granted permissions + to publish events to the channel. Format: `projects/{project}/locations/{location}/providers/{provider_id}`.' + x-kubernetes-immutable: true + pubsubTopic: + type: string + x-dcl-go-name: PubsubTopic + readOnly: true + description: 'Output only. The name of the Pub/Sub topic created and managed + by Eventarc system as a transport for the event delivery. Format: `projects/{project}/topics/{topic_id}`.' + x-kubernetes-immutable: true + state: + type: string + x-dcl-go-name: State + x-dcl-go-type: ChannelStateEnum + readOnly: true + description: 'Output only. The state of a Channel. Possible values: STATE_UNSPECIFIED, + PENDING, ACTIVE, INACTIVE' + x-kubernetes-immutable: true + enum: + - STATE_UNSPECIFIED + - PENDING + - ACTIVE + - INACTIVE + uid: + type: string + x-dcl-go-name: Uid + readOnly: true + description: Output only. Server assigned unique identifier for the channel. + The value is a UUID4 string and guaranteed to remain unchanged until the + resource is deleted. + x-kubernetes-immutable: true + updateTime: + type: string + format: date-time + x-dcl-go-name: UpdateTime + readOnly: true + description: Output only. The last-modified time. + x-kubernetes-immutable: true diff --git a/services/google/eventarc/channel_internal.go b/services/google/eventarc/channel_internal.go new file mode 100755 index 000000000..e172416bd --- /dev/null +++ b/services/google/eventarc/channel_internal.go @@ -0,0 +1,901 @@ +// Copyright 2022 Google LLC. All Rights Reserved. +// +// 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 eventarc + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io/ioutil" + "strings" + + "github.com/GoogleCloudPlatform/declarative-resource-client-library/dcl" + "github.com/GoogleCloudPlatform/declarative-resource-client-library/dcl/operations" +) + +func (r *Channel) validate() error { + + if err := dcl.Required(r, "name"); err != nil { + return err + } + if err := dcl.RequiredParameter(r.Project, "Project"); err != nil { + return err + } + if err := dcl.RequiredParameter(r.Location, "Location"); err != nil { + return err + } + return nil +} +func (r *Channel) basePath() string { + params := map[string]interface{}{} + return dcl.Nprintf("https://eventarc.googleapis.com/v1/", params) +} + +func (r *Channel) getURL(userBasePath string) (string, error) { + nr := r.urlNormalized() + params := map[string]interface{}{ + "project": dcl.ValueOrEmptyString(nr.Project), + "location": dcl.ValueOrEmptyString(nr.Location), + "name": dcl.ValueOrEmptyString(nr.Name), + } + return dcl.URL("projects/{{project}}/locations/{{location}}/channels/{{name}}", nr.basePath(), userBasePath, params), nil +} + +func (r *Channel) listURL(userBasePath string) (string, error) { + nr := r.urlNormalized() + params := map[string]interface{}{ + "project": dcl.ValueOrEmptyString(nr.Project), + "location": dcl.ValueOrEmptyString(nr.Location), + } + return dcl.URL("projects/{{project}}/locations/{{location}}/channels", nr.basePath(), userBasePath, params), nil + +} + +func (r *Channel) createURL(userBasePath string) (string, error) { + nr := r.urlNormalized() + params := map[string]interface{}{ + "project": dcl.ValueOrEmptyString(nr.Project), + "location": dcl.ValueOrEmptyString(nr.Location), + "name": dcl.ValueOrEmptyString(nr.Name), + } + return dcl.URL("projects/{{project}}/locations/{{location}}/channels?channelId={{name}}", nr.basePath(), userBasePath, params), nil + +} + +func (r *Channel) deleteURL(userBasePath string) (string, error) { + nr := r.urlNormalized() + params := map[string]interface{}{ + "project": dcl.ValueOrEmptyString(nr.Project), + "location": dcl.ValueOrEmptyString(nr.Location), + "name": dcl.ValueOrEmptyString(nr.Name), + } + return dcl.URL("projects/{{project}}/locations/{{location}}/channels/{{name}}", nr.basePath(), userBasePath, params), nil +} + +// channelApiOperation represents a mutable operation in the underlying REST +// API such as Create, Update, or Delete. +type channelApiOperation interface { + do(context.Context, *Channel, *Client) error +} + +// newUpdateChannelUpdateChannelRequest creates a request for an +// Channel resource's UpdateChannel update type by filling in the update +// fields based on the intended state of the resource. +func newUpdateChannelUpdateChannelRequest(ctx context.Context, f *Channel, c *Client) (map[string]interface{}, error) { + req := map[string]interface{}{} + res := f + _ = res + + if v := f.CryptoKeyName; !dcl.IsEmptyValueIndirect(v) { + req["cryptoKeyName"] = v + } + req["name"] = fmt.Sprintf("projects/%s/locations/%s/channels/%s", *f.Project, *f.Location, *f.Name) + + return req, nil +} + +// marshalUpdateChannelUpdateChannelRequest converts the update into +// the final JSON request body. +func marshalUpdateChannelUpdateChannelRequest(c *Client, m map[string]interface{}) ([]byte, error) { + + return json.Marshal(m) +} + +type updateChannelUpdateChannelOperation struct { + // If the update operation has the REQUIRES_APPLY_OPTIONS trait, this will be populated. + // Usually it will be nil - this is to prevent us from accidentally depending on apply + // options, which should usually be unnecessary. + ApplyOptions []dcl.ApplyOption + FieldDiffs []*dcl.FieldDiff +} + +// do creates a request and sends it to the appropriate URL. In most operations, +// do will transcribe a subset of the resource into a request object and send a +// PUT request to a single URL. + +func (op *updateChannelUpdateChannelOperation) do(ctx context.Context, r *Channel, c *Client) error { + _, err := c.GetChannel(ctx, r) + if err != nil { + return err + } + + u, err := r.updateURL(c.Config.BasePath, "UpdateChannel") + if err != nil { + return err + } + mask := dcl.UpdateMask(op.FieldDiffs) + u, err = dcl.AddQueryParams(u, map[string]string{"updateMask": mask}) + if err != nil { + return err + } + + req, err := newUpdateChannelUpdateChannelRequest(ctx, r, c) + if err != nil { + return err + } + + c.Config.Logger.InfoWithContextf(ctx, "Created update: %#v", req) + body, err := marshalUpdateChannelUpdateChannelRequest(c, req) + if err != nil { + return err + } + resp, err := dcl.SendRequest(ctx, c.Config, "PATCH", u, bytes.NewBuffer(body), c.Config.RetryProvider) + if err != nil { + return err + } + + var o operations.StandardGCPOperation + if err := dcl.ParseResponse(resp.Response, &o); err != nil { + return err + } + err = o.Wait(context.WithValue(ctx, dcl.DoNotLogRequestsKey, true), c.Config, r.basePath(), "GET") + + if err != nil { + return err + } + + return nil +} + +func (c *Client) listChannelRaw(ctx context.Context, r *Channel, pageToken string, pageSize int32) ([]byte, error) { + u, err := r.urlNormalized().listURL(c.Config.BasePath) + if err != nil { + return nil, err + } + + m := make(map[string]string) + if pageToken != "" { + m["pageToken"] = pageToken + } + + if pageSize != ChannelMaxPage { + m["pageSize"] = fmt.Sprintf("%v", pageSize) + } + + u, err = dcl.AddQueryParams(u, m) + if err != nil { + return nil, err + } + resp, err := dcl.SendRequest(ctx, c.Config, "GET", u, &bytes.Buffer{}, c.Config.RetryProvider) + if err != nil { + return nil, err + } + defer resp.Response.Body.Close() + return ioutil.ReadAll(resp.Response.Body) +} + +type listChannelOperation struct { + Channels []map[string]interface{} `json:"channels"` + Token string `json:"nextPageToken"` +} + +func (c *Client) listChannel(ctx context.Context, r *Channel, pageToken string, pageSize int32) ([]*Channel, string, error) { + b, err := c.listChannelRaw(ctx, r, pageToken, pageSize) + if err != nil { + return nil, "", err + } + + var m listChannelOperation + if err := json.Unmarshal(b, &m); err != nil { + return nil, "", err + } + + var l []*Channel + for _, v := range m.Channels { + res, err := unmarshalMapChannel(v, c, r) + if err != nil { + return nil, m.Token, err + } + res.Project = r.Project + res.Location = r.Location + l = append(l, res) + } + + return l, m.Token, nil +} + +func (c *Client) deleteAllChannel(ctx context.Context, f func(*Channel) bool, resources []*Channel) error { + var errors []string + for _, res := range resources { + if f(res) { + // We do not want deleteAll to fail on a deletion or else it will stop deleting other resources. + err := c.DeleteChannel(ctx, res) + if err != nil { + errors = append(errors, err.Error()) + } + } + } + if len(errors) > 0 { + return fmt.Errorf("%v", strings.Join(errors, "\n")) + } else { + return nil + } +} + +type deleteChannelOperation struct{} + +func (op *deleteChannelOperation) do(ctx context.Context, r *Channel, c *Client) error { + r, err := c.GetChannel(ctx, r) + if err != nil { + if dcl.IsNotFound(err) { + c.Config.Logger.InfoWithContextf(ctx, "Channel not found, returning. Original error: %v", err) + return nil + } + c.Config.Logger.WarningWithContextf(ctx, "GetChannel checking for existence. error: %v", err) + return err + } + + u, err := r.deleteURL(c.Config.BasePath) + if err != nil { + return err + } + + // Delete should never have a body + body := &bytes.Buffer{} + resp, err := dcl.SendRequest(ctx, c.Config, "DELETE", u, body, c.Config.RetryProvider) + if err != nil { + return err + } + + // wait for object to be deleted. + var o operations.StandardGCPOperation + if err := dcl.ParseResponse(resp.Response, &o); err != nil { + return err + } + if err := o.Wait(context.WithValue(ctx, dcl.DoNotLogRequestsKey, true), c.Config, r.basePath(), "GET"); err != nil { + return err + } + + // We saw a race condition where for some successful delete operation, the Get calls returned resources for a short duration. + // This is the reason we are adding retry to handle that case. + retriesRemaining := 10 + dcl.Do(ctx, func(ctx context.Context) (*dcl.RetryDetails, error) { + _, err := c.GetChannel(ctx, r) + if dcl.IsNotFound(err) { + return nil, nil + } + if retriesRemaining > 0 { + retriesRemaining-- + return &dcl.RetryDetails{}, dcl.OperationNotDone{} + } + return nil, dcl.NotDeletedError{ExistingResource: r} + }, c.Config.RetryProvider) + return nil +} + +// Create operations are similar to Update operations, although they do not have +// specific request objects. The Create request object is the json encoding of +// the resource, which is modified by res.marshal to form the base request body. +type createChannelOperation struct { + response map[string]interface{} +} + +func (op *createChannelOperation) FirstResponse() (map[string]interface{}, bool) { + return op.response, len(op.response) > 0 +} + +func (op *createChannelOperation) do(ctx context.Context, r *Channel, c *Client) error { + c.Config.Logger.InfoWithContextf(ctx, "Attempting to create %v", r) + u, err := r.createURL(c.Config.BasePath) + if err != nil { + return err + } + + req, err := r.marshal(c) + if err != nil { + return err + } + resp, err := dcl.SendRequest(ctx, c.Config, "POST", u, bytes.NewBuffer(req), c.Config.RetryProvider) + if err != nil { + return err + } + // wait for object to be created. + var o operations.StandardGCPOperation + if err := dcl.ParseResponse(resp.Response, &o); err != nil { + return err + } + if err := o.Wait(context.WithValue(ctx, dcl.DoNotLogRequestsKey, true), c.Config, r.basePath(), "GET"); err != nil { + c.Config.Logger.Warningf("Creation failed after waiting for operation: %v", err) + return err + } + c.Config.Logger.InfoWithContextf(ctx, "Successfully waited for operation") + op.response, _ = o.FirstResponse() + + if _, err := c.GetChannel(ctx, r); err != nil { + c.Config.Logger.WarningWithContextf(ctx, "get returned error: %v", err) + return err + } + + return nil +} + +func (c *Client) getChannelRaw(ctx context.Context, r *Channel) ([]byte, error) { + + u, err := r.getURL(c.Config.BasePath) + if err != nil { + return nil, err + } + resp, err := dcl.SendRequest(ctx, c.Config, "GET", u, &bytes.Buffer{}, c.Config.RetryProvider) + if err != nil { + return nil, err + } + defer resp.Response.Body.Close() + b, err := ioutil.ReadAll(resp.Response.Body) + if err != nil { + return nil, err + } + + return b, nil +} + +func (c *Client) channelDiffsForRawDesired(ctx context.Context, rawDesired *Channel, opts ...dcl.ApplyOption) (initial, desired *Channel, diffs []*dcl.FieldDiff, err error) { + c.Config.Logger.InfoWithContext(ctx, "Fetching initial state...") + // First, let us see if the user provided a state hint. If they did, we will start fetching based on that. + var fetchState *Channel + if sh := dcl.FetchStateHint(opts); sh != nil { + if r, ok := sh.(*Channel); !ok { + c.Config.Logger.WarningWithContextf(ctx, "Initial state hint was of the wrong type; expected Channel, got %T", sh) + } else { + fetchState = r + } + } + if fetchState == nil { + fetchState = rawDesired + } + + // 1.2: Retrieval of raw initial state from API + rawInitial, err := c.GetChannel(ctx, fetchState) + if rawInitial == nil { + if !dcl.IsNotFound(err) { + c.Config.Logger.WarningWithContextf(ctx, "Failed to retrieve whether a Channel resource already exists: %s", err) + return nil, nil, nil, fmt.Errorf("failed to retrieve Channel resource: %v", err) + } + c.Config.Logger.InfoWithContext(ctx, "Found that Channel resource did not exist.") + // Perform canonicalization to pick up defaults. + desired, err = canonicalizeChannelDesiredState(rawDesired, rawInitial) + return nil, desired, nil, err + } + c.Config.Logger.InfoWithContextf(ctx, "Found initial state for Channel: %v", rawInitial) + c.Config.Logger.InfoWithContextf(ctx, "Initial desired state for Channel: %v", rawDesired) + + // The Get call applies postReadExtract and so the result may contain fields that are not part of API version. + if err := extractChannelFields(rawInitial); err != nil { + return nil, nil, nil, err + } + + // 1.3: Canonicalize raw initial state into initial state. + initial, err = canonicalizeChannelInitialState(rawInitial, rawDesired) + if err != nil { + return nil, nil, nil, err + } + c.Config.Logger.InfoWithContextf(ctx, "Canonicalized initial state for Channel: %v", initial) + + // 1.4: Canonicalize raw desired state into desired state. + desired, err = canonicalizeChannelDesiredState(rawDesired, rawInitial, opts...) + if err != nil { + return nil, nil, nil, err + } + c.Config.Logger.InfoWithContextf(ctx, "Canonicalized desired state for Channel: %v", desired) + + // 2.1: Comparison of initial and desired state. + diffs, err = diffChannel(c, desired, initial, opts...) + return initial, desired, diffs, err +} + +func canonicalizeChannelInitialState(rawInitial, rawDesired *Channel) (*Channel, error) { + // TODO(magic-modules-eng): write canonicalizer once relevant traits are added. + return rawInitial, nil +} + +/* +* Canonicalizers +* +* These are responsible for converting either a user-specified config or a +* GCP API response to a standard format that can be used for difference checking. +* */ + +func canonicalizeChannelDesiredState(rawDesired, rawInitial *Channel, opts ...dcl.ApplyOption) (*Channel, error) { + + if rawInitial == nil { + // Since the initial state is empty, the desired state is all we have. + // We canonicalize the remaining nested objects with nil to pick up defaults. + + return rawDesired, nil + } + canonicalDesired := &Channel{} + if dcl.PartialSelfLinkToSelfLink(rawDesired.Name, rawInitial.Name) { + canonicalDesired.Name = rawInitial.Name + } else { + canonicalDesired.Name = rawDesired.Name + } + if dcl.StringCanonicalize(rawDesired.Provider, rawInitial.Provider) { + canonicalDesired.Provider = rawInitial.Provider + } else { + canonicalDesired.Provider = rawDesired.Provider + } + if dcl.IsZeroValue(rawDesired.CryptoKeyName) || (dcl.IsEmptyValueIndirect(rawDesired.CryptoKeyName) && dcl.IsEmptyValueIndirect(rawInitial.CryptoKeyName)) { + // Desired and initial values are equivalent, so set canonical desired value to initial value. + canonicalDesired.CryptoKeyName = rawInitial.CryptoKeyName + } else { + canonicalDesired.CryptoKeyName = rawDesired.CryptoKeyName + } + if dcl.NameToSelfLink(rawDesired.Project, rawInitial.Project) { + canonicalDesired.Project = rawInitial.Project + } else { + canonicalDesired.Project = rawDesired.Project + } + if dcl.NameToSelfLink(rawDesired.Location, rawInitial.Location) { + canonicalDesired.Location = rawInitial.Location + } else { + canonicalDesired.Location = rawDesired.Location + } + + return canonicalDesired, nil +} + +func canonicalizeChannelNewState(c *Client, rawNew, rawDesired *Channel) (*Channel, error) { + + if dcl.IsEmptyValueIndirect(rawNew.Name) && dcl.IsEmptyValueIndirect(rawDesired.Name) { + rawNew.Name = rawDesired.Name + } else { + if dcl.PartialSelfLinkToSelfLink(rawDesired.Name, rawNew.Name) { + rawNew.Name = rawDesired.Name + } + } + + if dcl.IsEmptyValueIndirect(rawNew.Uid) && dcl.IsEmptyValueIndirect(rawDesired.Uid) { + rawNew.Uid = rawDesired.Uid + } else { + if dcl.StringCanonicalize(rawDesired.Uid, rawNew.Uid) { + rawNew.Uid = rawDesired.Uid + } + } + + if dcl.IsEmptyValueIndirect(rawNew.CreateTime) && dcl.IsEmptyValueIndirect(rawDesired.CreateTime) { + rawNew.CreateTime = rawDesired.CreateTime + } else { + } + + if dcl.IsEmptyValueIndirect(rawNew.UpdateTime) && dcl.IsEmptyValueIndirect(rawDesired.UpdateTime) { + rawNew.UpdateTime = rawDesired.UpdateTime + } else { + } + + if dcl.IsEmptyValueIndirect(rawNew.Provider) && dcl.IsEmptyValueIndirect(rawDesired.Provider) { + rawNew.Provider = rawDesired.Provider + } else { + if dcl.StringCanonicalize(rawDesired.Provider, rawNew.Provider) { + rawNew.Provider = rawDesired.Provider + } + } + + if dcl.IsEmptyValueIndirect(rawNew.PubsubTopic) && dcl.IsEmptyValueIndirect(rawDesired.PubsubTopic) { + rawNew.PubsubTopic = rawDesired.PubsubTopic + } else { + if dcl.StringCanonicalize(rawDesired.PubsubTopic, rawNew.PubsubTopic) { + rawNew.PubsubTopic = rawDesired.PubsubTopic + } + } + + if dcl.IsEmptyValueIndirect(rawNew.State) && dcl.IsEmptyValueIndirect(rawDesired.State) { + rawNew.State = rawDesired.State + } else { + } + + if dcl.IsEmptyValueIndirect(rawNew.ActivationToken) && dcl.IsEmptyValueIndirect(rawDesired.ActivationToken) { + rawNew.ActivationToken = rawDesired.ActivationToken + } else { + if dcl.StringCanonicalize(rawDesired.ActivationToken, rawNew.ActivationToken) { + rawNew.ActivationToken = rawDesired.ActivationToken + } + } + + if dcl.IsEmptyValueIndirect(rawNew.CryptoKeyName) && dcl.IsEmptyValueIndirect(rawDesired.CryptoKeyName) { + rawNew.CryptoKeyName = rawDesired.CryptoKeyName + } else { + } + + rawNew.Project = rawDesired.Project + + rawNew.Location = rawDesired.Location + + return rawNew, nil +} + +// The differ returns a list of diffs, along with a list of operations that should be taken +// to remedy them. Right now, it does not attempt to consolidate operations - if several +// fields can be fixed with a patch update, it will perform the patch several times. +// Diffs on some fields will be ignored if the `desired` state has an empty (nil) +// value. This empty value indicates that the user does not care about the state for +// the field. Empty fields on the actual object will cause diffs. +// TODO(magic-modules-eng): for efficiency in some resources, add batching. +func diffChannel(c *Client, desired, actual *Channel, opts ...dcl.ApplyOption) ([]*dcl.FieldDiff, error) { + if desired == nil || actual == nil { + return nil, fmt.Errorf("nil resource passed to diff - always a programming error: %#v, %#v", desired, actual) + } + + c.Config.Logger.Infof("Diff function called with desired state: %v", desired) + c.Config.Logger.Infof("Diff function called with actual state: %v", actual) + + var fn dcl.FieldName + var newDiffs []*dcl.FieldDiff + // New style diffs. + if ds, err := dcl.Diff(desired.Name, actual.Name, dcl.DiffInfo{OperationSelector: dcl.RequiresRecreate()}, fn.AddNest("Name")); len(ds) != 0 || err != nil { + if err != nil { + return nil, err + } + newDiffs = append(newDiffs, ds...) + } + + if ds, err := dcl.Diff(desired.Uid, actual.Uid, dcl.DiffInfo{OutputOnly: true, OperationSelector: dcl.RequiresRecreate()}, fn.AddNest("Uid")); len(ds) != 0 || err != nil { + if err != nil { + return nil, err + } + newDiffs = append(newDiffs, ds...) + } + + if ds, err := dcl.Diff(desired.CreateTime, actual.CreateTime, dcl.DiffInfo{OutputOnly: true, OperationSelector: dcl.RequiresRecreate()}, fn.AddNest("CreateTime")); len(ds) != 0 || err != nil { + if err != nil { + return nil, err + } + newDiffs = append(newDiffs, ds...) + } + + if ds, err := dcl.Diff(desired.UpdateTime, actual.UpdateTime, dcl.DiffInfo{OutputOnly: true, OperationSelector: dcl.RequiresRecreate()}, fn.AddNest("UpdateTime")); len(ds) != 0 || err != nil { + if err != nil { + return nil, err + } + newDiffs = append(newDiffs, ds...) + } + + if ds, err := dcl.Diff(desired.Provider, actual.Provider, dcl.DiffInfo{OperationSelector: dcl.RequiresRecreate()}, fn.AddNest("Provider")); len(ds) != 0 || err != nil { + if err != nil { + return nil, err + } + newDiffs = append(newDiffs, ds...) + } + + if ds, err := dcl.Diff(desired.PubsubTopic, actual.PubsubTopic, dcl.DiffInfo{OutputOnly: true, OperationSelector: dcl.RequiresRecreate()}, fn.AddNest("PubsubTopic")); len(ds) != 0 || err != nil { + if err != nil { + return nil, err + } + newDiffs = append(newDiffs, ds...) + } + + if ds, err := dcl.Diff(desired.State, actual.State, dcl.DiffInfo{OutputOnly: true, Type: "EnumType", OperationSelector: dcl.RequiresRecreate()}, fn.AddNest("State")); len(ds) != 0 || err != nil { + if err != nil { + return nil, err + } + newDiffs = append(newDiffs, ds...) + } + + if ds, err := dcl.Diff(desired.ActivationToken, actual.ActivationToken, dcl.DiffInfo{OutputOnly: true, OperationSelector: dcl.RequiresRecreate()}, fn.AddNest("ActivationToken")); len(ds) != 0 || err != nil { + if err != nil { + return nil, err + } + newDiffs = append(newDiffs, ds...) + } + + if ds, err := dcl.Diff(desired.CryptoKeyName, actual.CryptoKeyName, dcl.DiffInfo{Type: "ReferenceType", OperationSelector: dcl.TriggersOperation("updateChannelUpdateChannelOperation")}, fn.AddNest("CryptoKeyName")); len(ds) != 0 || err != nil { + if err != nil { + return nil, err + } + newDiffs = append(newDiffs, ds...) + } + + if ds, err := dcl.Diff(desired.Project, actual.Project, dcl.DiffInfo{Type: "ReferenceType", OperationSelector: dcl.RequiresRecreate()}, fn.AddNest("Project")); len(ds) != 0 || err != nil { + if err != nil { + return nil, err + } + newDiffs = append(newDiffs, ds...) + } + + if ds, err := dcl.Diff(desired.Location, actual.Location, dcl.DiffInfo{OperationSelector: dcl.RequiresRecreate()}, fn.AddNest("Location")); len(ds) != 0 || err != nil { + if err != nil { + return nil, err + } + newDiffs = append(newDiffs, ds...) + } + + return newDiffs, nil +} + +// urlNormalized returns a copy of the resource struct with values normalized +// for URL substitutions. For instance, it converts long-form self-links to +// short-form so they can be substituted in. +func (r *Channel) urlNormalized() *Channel { + normalized := dcl.Copy(*r).(Channel) + normalized.Name = dcl.SelfLinkToName(r.Name) + normalized.Uid = dcl.SelfLinkToName(r.Uid) + normalized.Provider = dcl.SelfLinkToName(r.Provider) + normalized.PubsubTopic = dcl.SelfLinkToName(r.PubsubTopic) + normalized.ActivationToken = dcl.SelfLinkToName(r.ActivationToken) + normalized.CryptoKeyName = r.CryptoKeyName + normalized.Project = dcl.SelfLinkToName(r.Project) + normalized.Location = dcl.SelfLinkToName(r.Location) + return &normalized +} + +func (r *Channel) updateURL(userBasePath, updateName string) (string, error) { + nr := r.urlNormalized() + if updateName == "UpdateChannel" { + fields := map[string]interface{}{ + "project": dcl.ValueOrEmptyString(nr.Project), + "location": dcl.ValueOrEmptyString(nr.Location), + "name": dcl.ValueOrEmptyString(nr.Name), + } + return dcl.URL("projects/{{project}}/locations/{{location}}/channels/{{name}}", nr.basePath(), userBasePath, fields), nil + + } + + return "", fmt.Errorf("unknown update name: %s", updateName) +} + +// marshal encodes the Channel resource into JSON for a Create request, and +// performs transformations from the resource schema to the API schema if +// necessary. +func (r *Channel) marshal(c *Client) ([]byte, error) { + m, err := expandChannel(c, r) + if err != nil { + return nil, fmt.Errorf("error marshalling Channel: %w", err) + } + + return json.Marshal(m) +} + +// unmarshalChannel decodes JSON responses into the Channel resource schema. +func unmarshalChannel(b []byte, c *Client, res *Channel) (*Channel, error) { + var m map[string]interface{} + if err := json.Unmarshal(b, &m); err != nil { + return nil, err + } + return unmarshalMapChannel(m, c, res) +} + +func unmarshalMapChannel(m map[string]interface{}, c *Client, res *Channel) (*Channel, error) { + + flattened := flattenChannel(c, m, res) + if flattened == nil { + return nil, fmt.Errorf("attempted to flatten empty json object") + } + return flattened, nil +} + +// expandChannel expands Channel into a JSON request object. +func expandChannel(c *Client, f *Channel) (map[string]interface{}, error) { + m := make(map[string]interface{}) + res := f + _ = res + if v, err := dcl.DeriveField("projects/%s/locations/%s/channels/%s", f.Name, dcl.SelfLinkToName(f.Project), dcl.SelfLinkToName(f.Location), dcl.SelfLinkToName(f.Name)); err != nil { + return nil, fmt.Errorf("error expanding Name into name: %w", err) + } else if !dcl.IsEmptyValueIndirect(v) { + m["name"] = v + } + if v := f.Provider; dcl.ValueShouldBeSent(v) { + m["provider"] = v + } + if v := f.CryptoKeyName; dcl.ValueShouldBeSent(v) { + m["cryptoKeyName"] = v + } + if v, err := dcl.EmptyValue(); err != nil { + return nil, fmt.Errorf("error expanding Project into project: %w", err) + } else if !dcl.IsEmptyValueIndirect(v) { + m["project"] = v + } + if v, err := dcl.EmptyValue(); err != nil { + return nil, fmt.Errorf("error expanding Location into location: %w", err) + } else if !dcl.IsEmptyValueIndirect(v) { + m["location"] = v + } + + return m, nil +} + +// flattenChannel flattens Channel from a JSON request object into the +// Channel type. +func flattenChannel(c *Client, i interface{}, res *Channel) *Channel { + m, ok := i.(map[string]interface{}) + if !ok { + return nil + } + if len(m) == 0 { + return nil + } + + resultRes := &Channel{} + resultRes.Name = dcl.FlattenString(m["name"]) + resultRes.Uid = dcl.FlattenString(m["uid"]) + resultRes.CreateTime = dcl.FlattenString(m["createTime"]) + resultRes.UpdateTime = dcl.FlattenString(m["updateTime"]) + resultRes.Provider = dcl.FlattenString(m["provider"]) + resultRes.PubsubTopic = dcl.FlattenString(m["pubsubTopic"]) + resultRes.State = flattenChannelStateEnum(m["state"]) + resultRes.ActivationToken = dcl.FlattenString(m["activationToken"]) + resultRes.CryptoKeyName = dcl.FlattenString(m["cryptoKeyName"]) + resultRes.Project = dcl.FlattenString(m["project"]) + resultRes.Location = dcl.FlattenString(m["location"]) + + return resultRes +} + +// flattenChannelStateEnumMap flattens the contents of ChannelStateEnum from a JSON +// response object. +func flattenChannelStateEnumMap(c *Client, i interface{}, res *Channel) map[string]ChannelStateEnum { + a, ok := i.(map[string]interface{}) + if !ok { + return map[string]ChannelStateEnum{} + } + + if len(a) == 0 { + return map[string]ChannelStateEnum{} + } + + items := make(map[string]ChannelStateEnum) + for k, item := range a { + items[k] = *flattenChannelStateEnum(item.(interface{})) + } + + return items +} + +// flattenChannelStateEnumSlice flattens the contents of ChannelStateEnum from a JSON +// response object. +func flattenChannelStateEnumSlice(c *Client, i interface{}, res *Channel) []ChannelStateEnum { + a, ok := i.([]interface{}) + if !ok { + return []ChannelStateEnum{} + } + + if len(a) == 0 { + return []ChannelStateEnum{} + } + + items := make([]ChannelStateEnum, 0, len(a)) + for _, item := range a { + items = append(items, *flattenChannelStateEnum(item.(interface{}))) + } + + return items +} + +// flattenChannelStateEnum asserts that an interface is a string, and returns a +// pointer to a *ChannelStateEnum with the same value as that string. +func flattenChannelStateEnum(i interface{}) *ChannelStateEnum { + s, ok := i.(string) + if !ok { + return nil + } + + return ChannelStateEnumRef(s) +} + +// This function returns a matcher that checks whether a serialized resource matches this resource +// in its parameters (as defined by the fields in a Get, which definitionally define resource +// identity). This is useful in extracting the element from a List call. +func (r *Channel) matcher(c *Client) func([]byte) bool { + return func(b []byte) bool { + cr, err := unmarshalChannel(b, c, r) + if err != nil { + c.Config.Logger.Warning("failed to unmarshal provided resource in matcher.") + return false + } + nr := r.urlNormalized() + ncr := cr.urlNormalized() + c.Config.Logger.Infof("looking for %v\nin %v", nr, ncr) + + if nr.Project == nil && ncr.Project == nil { + c.Config.Logger.Info("Both Project fields null - considering equal.") + } else if nr.Project == nil || ncr.Project == nil { + c.Config.Logger.Info("Only one Project field is null - considering unequal.") + return false + } else if *nr.Project != *ncr.Project { + return false + } + if nr.Location == nil && ncr.Location == nil { + c.Config.Logger.Info("Both Location fields null - considering equal.") + } else if nr.Location == nil || ncr.Location == nil { + c.Config.Logger.Info("Only one Location field is null - considering unequal.") + return false + } else if *nr.Location != *ncr.Location { + return false + } + if nr.Name == nil && ncr.Name == nil { + c.Config.Logger.Info("Both Name fields null - considering equal.") + } else if nr.Name == nil || ncr.Name == nil { + c.Config.Logger.Info("Only one Name field is null - considering unequal.") + return false + } else if *nr.Name != *ncr.Name { + return false + } + return true + } +} + +type channelDiff struct { + // The diff should include one or the other of RequiresRecreate or UpdateOp. + RequiresRecreate bool + UpdateOp channelApiOperation +} + +func convertFieldDiffsToChannelDiffs(config *dcl.Config, fds []*dcl.FieldDiff, opts []dcl.ApplyOption) ([]channelDiff, error) { + opNamesToFieldDiffs := make(map[string][]*dcl.FieldDiff) + // Map each operation name to the field diffs associated with it. + for _, fd := range fds { + for _, ro := range fd.ResultingOperation { + if fieldDiffs, ok := opNamesToFieldDiffs[ro]; ok { + fieldDiffs = append(fieldDiffs, fd) + opNamesToFieldDiffs[ro] = fieldDiffs + } else { + config.Logger.Infof("%s required due to diff: %v", ro, fd) + opNamesToFieldDiffs[ro] = []*dcl.FieldDiff{fd} + } + } + } + var diffs []channelDiff + // For each operation name, create a channelDiff which contains the operation. + for opName, fieldDiffs := range opNamesToFieldDiffs { + diff := channelDiff{} + if opName == "Recreate" { + diff.RequiresRecreate = true + } else { + apiOp, err := convertOpNameToChannelApiOperation(opName, fieldDiffs, opts...) + if err != nil { + return diffs, err + } + diff.UpdateOp = apiOp + } + diffs = append(diffs, diff) + } + return diffs, nil +} + +func convertOpNameToChannelApiOperation(opName string, fieldDiffs []*dcl.FieldDiff, opts ...dcl.ApplyOption) (channelApiOperation, error) { + switch opName { + + case "updateChannelUpdateChannelOperation": + return &updateChannelUpdateChannelOperation{FieldDiffs: fieldDiffs}, nil + + default: + return nil, fmt.Errorf("no such operation with name: %v", opName) + } +} + +func extractChannelFields(r *Channel) error { + return nil +} + +func postReadExtractChannelFields(r *Channel) error { + return nil +} diff --git a/services/google/eventarc/channel_schema.go b/services/google/eventarc/channel_schema.go new file mode 100755 index 000000000..4c23e496c --- /dev/null +++ b/services/google/eventarc/channel_schema.go @@ -0,0 +1,211 @@ +// Copyright 2022 Google LLC. All Rights Reserved. +// +// 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 eventarc + +import ( + "github.com/GoogleCloudPlatform/declarative-resource-client-library/dcl" +) + +func DCLChannelSchema() *dcl.Schema { + return &dcl.Schema{ + Info: &dcl.Info{ + Title: "Eventarc/Channel", + Description: "The Eventarc Channel resource", + StructName: "Channel", + }, + Paths: &dcl.Paths{ + Get: &dcl.Path{ + Description: "The function used to get information about a Channel", + Parameters: []dcl.PathParameters{ + dcl.PathParameters{ + Name: "Channel", + Required: true, + Description: "A full instance of a Channel", + }, + }, + }, + Apply: &dcl.Path{ + Description: "The function used to apply information about a Channel", + Parameters: []dcl.PathParameters{ + dcl.PathParameters{ + Name: "Channel", + Required: true, + Description: "A full instance of a Channel", + }, + }, + }, + Delete: &dcl.Path{ + Description: "The function used to delete a Channel", + Parameters: []dcl.PathParameters{ + dcl.PathParameters{ + Name: "Channel", + Required: true, + Description: "A full instance of a Channel", + }, + }, + }, + DeleteAll: &dcl.Path{ + Description: "The function used to delete all Channel", + Parameters: []dcl.PathParameters{ + dcl.PathParameters{ + Name: "project", + Required: true, + Schema: &dcl.PathParametersSchema{ + Type: "string", + }, + }, + dcl.PathParameters{ + Name: "location", + Required: true, + Schema: &dcl.PathParametersSchema{ + Type: "string", + }, + }, + }, + }, + List: &dcl.Path{ + Description: "The function used to list information about many Channel", + Parameters: []dcl.PathParameters{ + dcl.PathParameters{ + Name: "project", + Required: true, + Schema: &dcl.PathParametersSchema{ + Type: "string", + }, + }, + dcl.PathParameters{ + Name: "location", + Required: true, + Schema: &dcl.PathParametersSchema{ + Type: "string", + }, + }, + }, + }, + }, + Components: &dcl.Components{ + Schemas: map[string]*dcl.Component{ + "Channel": &dcl.Component{ + Title: "Channel", + ID: "projects/{{project}}/locations/{{location}}/channels/{{name}}", + ParentContainer: "project", + HasCreate: true, + SchemaProperty: dcl.Property{ + Type: "object", + Required: []string{ + "name", + "project", + "location", + }, + Properties: map[string]*dcl.Property{ + "activationToken": &dcl.Property{ + Type: "string", + GoName: "ActivationToken", + ReadOnly: true, + Description: "Output only. The activation token for the channel. The token must be used by the provider to register the channel for publishing.", + Immutable: true, + }, + "createTime": &dcl.Property{ + Type: "string", + Format: "date-time", + GoName: "CreateTime", + ReadOnly: true, + Description: "Output only. The creation time.", + Immutable: true, + }, + "cryptoKeyName": &dcl.Property{ + Type: "string", + GoName: "CryptoKeyName", + Description: "Optional. Resource name of a KMS crypto key (managed by the user) used to encrypt/decrypt their event data. It must match the pattern `projects/*/locations/*/keyRings/*/cryptoKeys/*`.", + ResourceReferences: []*dcl.PropertyResourceReference{ + &dcl.PropertyResourceReference{ + Resource: "Cloudkms/CryptoKey", + Field: "selfLink", + }, + }, + }, + "location": &dcl.Property{ + Type: "string", + GoName: "Location", + Description: "The location for the resource", + Immutable: true, + }, + "name": &dcl.Property{ + Type: "string", + GoName: "Name", + Description: "Required. The resource name of the channel. Must be unique within the location on the project and must be in `projects/{project}/locations/{location}/channels/{channel_id}` format.", + Immutable: true, + }, + "project": &dcl.Property{ + Type: "string", + GoName: "Project", + Description: "The project for the resource", + Immutable: true, + ResourceReferences: []*dcl.PropertyResourceReference{ + &dcl.PropertyResourceReference{ + Resource: "Cloudresourcemanager/Project", + Field: "name", + Parent: true, + }, + }, + }, + "provider": &dcl.Property{ + Type: "string", + GoName: "Provider", + Description: "The name of the event provider (e.g. Eventarc SaaS partner) associated with the channel. This provider will be granted permissions to publish events to the channel. Format: `projects/{project}/locations/{location}/providers/{provider_id}`.", + Immutable: true, + }, + "pubsubTopic": &dcl.Property{ + Type: "string", + GoName: "PubsubTopic", + ReadOnly: true, + Description: "Output only. The name of the Pub/Sub topic created and managed by Eventarc system as a transport for the event delivery. Format: `projects/{project}/topics/{topic_id}`.", + Immutable: true, + }, + "state": &dcl.Property{ + Type: "string", + GoName: "State", + GoType: "ChannelStateEnum", + ReadOnly: true, + Description: "Output only. The state of a Channel. Possible values: STATE_UNSPECIFIED, PENDING, ACTIVE, INACTIVE", + Immutable: true, + Enum: []string{ + "STATE_UNSPECIFIED", + "PENDING", + "ACTIVE", + "INACTIVE", + }, + }, + "uid": &dcl.Property{ + Type: "string", + GoName: "Uid", + ReadOnly: true, + Description: "Output only. Server assigned unique identifier for the channel. The value is a UUID4 string and guaranteed to remain unchanged until the resource is deleted.", + Immutable: true, + }, + "updateTime": &dcl.Property{ + Type: "string", + Format: "date-time", + GoName: "UpdateTime", + ReadOnly: true, + Description: "Output only. The last-modified time.", + Immutable: true, + }, + }, + }, + }, + }, + }, + } +} diff --git a/services/google/eventarc/channel_yaml_embed.go b/services/google/eventarc/channel_yaml_embed.go new file mode 100755 index 000000000..20171d87d --- /dev/null +++ b/services/google/eventarc/channel_yaml_embed.go @@ -0,0 +1,23 @@ +// Copyright 2022 Google LLC. All Rights Reserved. +// +// 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. +// GENERATED BY gen_go_data.go +// gen_go_data -package eventarc -var YAML_channel blaze-out/k8-fastbuild/genfiles/cloud/graphite/mmv2/services/google/eventarc/channel.yaml + +package eventarc + +// blaze-out/k8-fastbuild/genfiles/cloud/graphite/mmv2/services/google/eventarc/channel.yaml +var YAML_channel = []byte("info:\n title: Eventarc/Channel\n description: The Eventarc Channel resource\n x-dcl-struct-name: Channel\n x-dcl-has-iam: false\npaths:\n get:\n description: The function used to get information about a Channel\n parameters:\n - name: Channel\n required: true\n description: A full instance of a Channel\n apply:\n description: The function used to apply information about a Channel\n parameters:\n - name: Channel\n required: true\n description: A full instance of a Channel\n delete:\n description: The function used to delete a Channel\n parameters:\n - name: Channel\n required: true\n description: A full instance of a Channel\n deleteAll:\n description: The function used to delete all Channel\n parameters:\n - name: project\n required: true\n schema:\n type: string\n - name: location\n required: true\n schema:\n type: string\n list:\n description: The function used to list information about many Channel\n parameters:\n - name: project\n required: true\n schema:\n type: string\n - name: location\n required: true\n schema:\n type: string\ncomponents:\n schemas:\n Channel:\n title: Channel\n x-dcl-id: projects/{{project}}/locations/{{location}}/channels/{{name}}\n x-dcl-parent-container: project\n x-dcl-has-create: true\n x-dcl-has-iam: false\n x-dcl-read-timeout: 0\n x-dcl-apply-timeout: 0\n x-dcl-delete-timeout: 0\n type: object\n required:\n - name\n - project\n - location\n properties:\n activationToken:\n type: string\n x-dcl-go-name: ActivationToken\n readOnly: true\n description: Output only. The activation token for the channel. The token\n must be used by the provider to register the channel for publishing.\n x-kubernetes-immutable: true\n createTime:\n type: string\n format: date-time\n x-dcl-go-name: CreateTime\n readOnly: true\n description: Output only. The creation time.\n x-kubernetes-immutable: true\n cryptoKeyName:\n type: string\n x-dcl-go-name: CryptoKeyName\n description: Optional. Resource name of a KMS crypto key (managed by the\n user) used to encrypt/decrypt their event data. It must match the pattern\n `projects/*/locations/*/keyRings/*/cryptoKeys/*`.\n x-dcl-references:\n - resource: Cloudkms/CryptoKey\n field: selfLink\n location:\n type: string\n x-dcl-go-name: Location\n description: The location for the resource\n x-kubernetes-immutable: true\n name:\n type: string\n x-dcl-go-name: Name\n description: Required. The resource name of the channel. Must be unique\n within the location on the project and must be in `projects/{project}/locations/{location}/channels/{channel_id}`\n format.\n x-kubernetes-immutable: true\n project:\n type: string\n x-dcl-go-name: Project\n description: The project for the resource\n x-kubernetes-immutable: true\n x-dcl-references:\n - resource: Cloudresourcemanager/Project\n field: name\n parent: true\n provider:\n type: string\n x-dcl-go-name: Provider\n description: 'The name of the event provider (e.g. Eventarc SaaS partner)\n associated with the channel. This provider will be granted permissions\n to publish events to the channel. Format: `projects/{project}/locations/{location}/providers/{provider_id}`.'\n x-kubernetes-immutable: true\n pubsubTopic:\n type: string\n x-dcl-go-name: PubsubTopic\n readOnly: true\n description: 'Output only. The name of the Pub/Sub topic created and managed\n by Eventarc system as a transport for the event delivery. Format: `projects/{project}/topics/{topic_id}`.'\n x-kubernetes-immutable: true\n state:\n type: string\n x-dcl-go-name: State\n x-dcl-go-type: ChannelStateEnum\n readOnly: true\n description: 'Output only. The state of a Channel. Possible values: STATE_UNSPECIFIED,\n PENDING, ACTIVE, INACTIVE'\n x-kubernetes-immutable: true\n enum:\n - STATE_UNSPECIFIED\n - PENDING\n - ACTIVE\n - INACTIVE\n uid:\n type: string\n x-dcl-go-name: Uid\n readOnly: true\n description: Output only. Server assigned unique identifier for the channel.\n The value is a UUID4 string and guaranteed to remain unchanged until the\n resource is deleted.\n x-kubernetes-immutable: true\n updateTime:\n type: string\n format: date-time\n x-dcl-go-name: UpdateTime\n readOnly: true\n description: Output only. The last-modified time.\n x-kubernetes-immutable: true\n") + +// 5065 bytes +// MD5: 3c9ef5d33aaeccf49e297775a3ddc3ac diff --git a/services/google/eventarc/samples/basic.channel.json b/services/google/eventarc/samples/basic.channel.json new file mode 100755 index 000000000..5f6865086 --- /dev/null +++ b/services/google/eventarc/samples/basic.channel.json @@ -0,0 +1,7 @@ +{ + "name": "{{channel}}", + "project": "{{project}}", + "location": "{{region}}", + "cryptoKeyName": "projects/{{project}}/locations/{{region}}/keyRings/{{ref:minimal.cloudkms.key_ring.json:name}}/cryptoKeys/{{ref:first.cloudkms.crypto_key.json:name}}", + "provider": "projects/{{project}}/locations/{{region}}/providers/datadog" + } diff --git a/services/google/eventarc/samples/basic_channel.yaml b/services/google/eventarc/samples/basic_channel.yaml new file mode 100755 index 000000000..6252b828c --- /dev/null +++ b/services/google/eventarc/samples/basic_channel.yaml @@ -0,0 +1,42 @@ +# Copyright 2022 Google LLC. All Rights Reserved. +# +# 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. +name: basic_channel +description: A basic example for an Eventarc Channel +type: channel +versions: +- ga +resource: samples/basic.channel.json +dependencies: +- samples/first_crypto_key_encrypter_decrypter.iam.binding.json +- samples/second_crypto_key_encrypter_decrypter.iam.binding.json +- samples/second.cloudkms.crypto_key.json +- samples/minimal.cloudkms.key_ring.json +- samples/first.cloudkms.crypto_key.json +updates: +- resource: samples/update.channel.json + dependencies: + - samples/first_crypto_key_encrypter_decrypter.iam.binding.json + - samples/second_crypto_key_encrypter_decrypter.iam.binding.json + - samples/second.cloudkms.crypto_key.json + - samples/minimal.cloudkms.key_ring.json + - samples/first.cloudkms.crypto_key.json +variables: +- name: channel + type: resource_name +- name: project + type: project +- name: project_number + type: project_number +- name: region + type: region diff --git a/services/google/eventarc/samples/first.cloudkms.crypto_key.json b/services/google/eventarc/samples/first.cloudkms.crypto_key.json new file mode 100755 index 000000000..459fd15aa --- /dev/null +++ b/services/google/eventarc/samples/first.cloudkms.crypto_key.json @@ -0,0 +1,7 @@ +{ + "name": "test-key", + "project": "{{project}}", + "location": "{{region}}", + "keyRing": "{{ref:minimal.cloudkms.key_ring.json:name}}", + "purpose": "ENCRYPT_DECRYPT" +} diff --git a/services/google/eventarc/samples/first_crypto_key_encrypter_decrypter.iam.binding.json b/services/google/eventarc/samples/first_crypto_key_encrypter_decrypter.iam.binding.json new file mode 100755 index 000000000..5e6f1d2e3 --- /dev/null +++ b/services/google/eventarc/samples/first_crypto_key_encrypter_decrypter.iam.binding.json @@ -0,0 +1,5 @@ +{ + "role": "roles/cloudkms.cryptoKeyEncrypterDecrypter", + "members": ["serviceAccount:service-{{project_number}}@gcp-sa-eventarc.iam.gserviceaccount.com"], + "resource": "{{ref:first.cloudkms.crypto_key.json:__resource__}}" +} diff --git a/services/google/eventarc/samples/minimal.channel.json b/services/google/eventarc/samples/minimal.channel.json new file mode 100755 index 000000000..56536300f --- /dev/null +++ b/services/google/eventarc/samples/minimal.channel.json @@ -0,0 +1,5 @@ +{ + "name": "{{channel}}", + "project": "{{project}}", + "location": "{{region}}" + } diff --git a/services/google/eventarc/samples/minimal.cloudkms.key_ring.json b/services/google/eventarc/samples/minimal.cloudkms.key_ring.json new file mode 100755 index 000000000..b5bbf2d3f --- /dev/null +++ b/services/google/eventarc/samples/minimal.cloudkms.key_ring.json @@ -0,0 +1,5 @@ +{ + "name": "test-ring", + "project": "{{project}}", + "location": "{{region}}" +} diff --git a/services/google/eventarc/samples/minimal_channel.yaml b/services/google/eventarc/samples/minimal_channel.yaml new file mode 100755 index 000000000..bce8f12cc --- /dev/null +++ b/services/google/eventarc/samples/minimal_channel.yaml @@ -0,0 +1,26 @@ +# Copyright 2022 Google LLC. All Rights Reserved. +# +# 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. +name: minimal_channel +description: A basic example for an Eventarc Channel +type: channel +versions: +- ga +resource: samples/minimal.channel.json +variables: +- name: channel + type: resource_name +- name: project + type: project +- name: region + type: region diff --git a/services/google/eventarc/samples/second.cloudkms.crypto_key.json b/services/google/eventarc/samples/second.cloudkms.crypto_key.json new file mode 100755 index 000000000..00e483a86 --- /dev/null +++ b/services/google/eventarc/samples/second.cloudkms.crypto_key.json @@ -0,0 +1,7 @@ +{ + "name": "test-key-2", + "project": "{{project}}", + "location": "{{region}}", + "keyRing": "{{ref:minimal.cloudkms.key_ring.json:name}}", + "purpose": "ENCRYPT_DECRYPT" +} diff --git a/services/google/eventarc/samples/second_crypto_key_encrypter_decrypter.iam.binding.json b/services/google/eventarc/samples/second_crypto_key_encrypter_decrypter.iam.binding.json new file mode 100755 index 000000000..5ef7956dd --- /dev/null +++ b/services/google/eventarc/samples/second_crypto_key_encrypter_decrypter.iam.binding.json @@ -0,0 +1,6 @@ +{ + "role": "roles/cloudkms.cryptoKeyEncrypterDecrypter", + "members": ["serviceAccount:service-{{project_number}}@gcp-sa-eventarc.iam.gserviceaccount.com"], + "resource": "{{ref:second.cloudkms.crypto_key.json:__resource__}}" +} + diff --git a/services/google/eventarc/samples/update.channel.json b/services/google/eventarc/samples/update.channel.json new file mode 100755 index 000000000..b218f907c --- /dev/null +++ b/services/google/eventarc/samples/update.channel.json @@ -0,0 +1,7 @@ +{ + "name": "{{channel}}", + "project": "{{project}}", + "location": "{{region}}", + "cryptoKeyName": "projects/{{project}}/locations/{{region}}/keyRings/{{ref:minimal.cloudkms.key_ring.json:name}}/cryptoKeys/{{ref:second.cloudkms.crypto_key.json:name}}", + "provider": "projects/{{project}}/locations/{{region}}/providers/datadog" +} diff --git a/unstructured/google/eventarc/alpha/channel.go b/unstructured/google/eventarc/alpha/channel.go new file mode 100755 index 000000000..d95b9e94f --- /dev/null +++ b/unstructured/google/eventarc/alpha/channel.go @@ -0,0 +1,302 @@ +// Copyright 2022 Google LLC. All Rights Reserved. +// +// 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 eventarc + +import ( + "context" + "fmt" + "github.com/GoogleCloudPlatform/declarative-resource-client-library/dcl" + dclService "github.com/GoogleCloudPlatform/declarative-resource-client-library/services/google/eventarc/alpha" + "github.com/GoogleCloudPlatform/declarative-resource-client-library/unstructured" +) + +type Channel struct{} + +func ChannelToUnstructured(r *dclService.Channel) *unstructured.Resource { + u := &unstructured.Resource{ + STV: unstructured.ServiceTypeVersion{ + Service: "eventarc", + Version: "alpha", + Type: "Channel", + }, + Object: make(map[string]interface{}), + } + if r.ActivationToken != nil { + u.Object["activationToken"] = *r.ActivationToken + } + if r.CreateTime != nil { + u.Object["createTime"] = *r.CreateTime + } + if r.CryptoKeyName != nil { + u.Object["cryptoKeyName"] = *r.CryptoKeyName + } + if r.Location != nil { + u.Object["location"] = *r.Location + } + if r.Name != nil { + u.Object["name"] = *r.Name + } + if r.Project != nil { + u.Object["project"] = *r.Project + } + if r.Provider != nil { + u.Object["provider"] = *r.Provider + } + if r.PubsubTopic != nil { + u.Object["pubsubTopic"] = *r.PubsubTopic + } + if r.State != nil { + u.Object["state"] = string(*r.State) + } + if r.Uid != nil { + u.Object["uid"] = *r.Uid + } + if r.UpdateTime != nil { + u.Object["updateTime"] = *r.UpdateTime + } + return u +} + +func UnstructuredToChannel(u *unstructured.Resource) (*dclService.Channel, error) { + r := &dclService.Channel{} + if _, ok := u.Object["activationToken"]; ok { + if s, ok := u.Object["activationToken"].(string); ok { + r.ActivationToken = dcl.String(s) + } else { + return nil, fmt.Errorf("r.ActivationToken: expected string") + } + } + if _, ok := u.Object["createTime"]; ok { + if s, ok := u.Object["createTime"].(string); ok { + r.CreateTime = dcl.String(s) + } else { + return nil, fmt.Errorf("r.CreateTime: expected string") + } + } + if _, ok := u.Object["cryptoKeyName"]; ok { + if s, ok := u.Object["cryptoKeyName"].(string); ok { + r.CryptoKeyName = dcl.String(s) + } else { + return nil, fmt.Errorf("r.CryptoKeyName: expected string") + } + } + if _, ok := u.Object["location"]; ok { + if s, ok := u.Object["location"].(string); ok { + r.Location = dcl.String(s) + } else { + return nil, fmt.Errorf("r.Location: expected string") + } + } + if _, ok := u.Object["name"]; ok { + if s, ok := u.Object["name"].(string); ok { + r.Name = dcl.String(s) + } else { + return nil, fmt.Errorf("r.Name: expected string") + } + } + if _, ok := u.Object["project"]; ok { + if s, ok := u.Object["project"].(string); ok { + r.Project = dcl.String(s) + } else { + return nil, fmt.Errorf("r.Project: expected string") + } + } + if _, ok := u.Object["provider"]; ok { + if s, ok := u.Object["provider"].(string); ok { + r.Provider = dcl.String(s) + } else { + return nil, fmt.Errorf("r.Provider: expected string") + } + } + if _, ok := u.Object["pubsubTopic"]; ok { + if s, ok := u.Object["pubsubTopic"].(string); ok { + r.PubsubTopic = dcl.String(s) + } else { + return nil, fmt.Errorf("r.PubsubTopic: expected string") + } + } + if _, ok := u.Object["state"]; ok { + if s, ok := u.Object["state"].(string); ok { + r.State = dclService.ChannelStateEnumRef(s) + } else { + return nil, fmt.Errorf("r.State: expected string") + } + } + if _, ok := u.Object["uid"]; ok { + if s, ok := u.Object["uid"].(string); ok { + r.Uid = dcl.String(s) + } else { + return nil, fmt.Errorf("r.Uid: expected string") + } + } + if _, ok := u.Object["updateTime"]; ok { + if s, ok := u.Object["updateTime"].(string); ok { + r.UpdateTime = dcl.String(s) + } else { + return nil, fmt.Errorf("r.UpdateTime: expected string") + } + } + return r, nil +} + +func GetChannel(ctx context.Context, config *dcl.Config, u *unstructured.Resource) (*unstructured.Resource, error) { + c := dclService.NewClient(config) + r, err := UnstructuredToChannel(u) + if err != nil { + return nil, err + } + r, err = c.GetChannel(ctx, r) + if err != nil { + return nil, err + } + return ChannelToUnstructured(r), nil +} + +func ListChannel(ctx context.Context, config *dcl.Config, project string, location string) ([]*unstructured.Resource, error) { + c := dclService.NewClient(config) + l, err := c.ListChannel(ctx, project, location) + if err != nil { + return nil, err + } + var resources []*unstructured.Resource + for { + for _, r := range l.Items { + resources = append(resources, ChannelToUnstructured(r)) + } + if !l.HasNext() { + break + } + if err := l.Next(ctx, c); err != nil { + return nil, err + } + } + return resources, nil +} + +func ApplyChannel(ctx context.Context, config *dcl.Config, u *unstructured.Resource, opts ...dcl.ApplyOption) (*unstructured.Resource, error) { + c := dclService.NewClient(config) + r, err := UnstructuredToChannel(u) + if err != nil { + return nil, err + } + if ush := unstructured.FetchStateHint(opts); ush != nil { + sh, err := UnstructuredToChannel(ush) + if err != nil { + return nil, err + } + opts = append(opts, dcl.WithStateHint(sh)) + } + r, err = c.ApplyChannel(ctx, r, opts...) + if err != nil { + return nil, err + } + return ChannelToUnstructured(r), nil +} + +func ChannelHasDiff(ctx context.Context, config *dcl.Config, u *unstructured.Resource, opts ...dcl.ApplyOption) (bool, error) { + c := dclService.NewClient(config) + r, err := UnstructuredToChannel(u) + if err != nil { + return false, err + } + if ush := unstructured.FetchStateHint(opts); ush != nil { + sh, err := UnstructuredToChannel(ush) + if err != nil { + return false, err + } + opts = append(opts, dcl.WithStateHint(sh)) + } + opts = append(opts, dcl.WithLifecycleParam(dcl.BlockDestruction), dcl.WithLifecycleParam(dcl.BlockCreation), dcl.WithLifecycleParam(dcl.BlockModification)) + _, err = c.ApplyChannel(ctx, r, opts...) + if err != nil { + if _, ok := err.(dcl.ApplyInfeasibleError); ok { + return true, nil + } + return false, err + } + return false, nil +} + +func DeleteChannel(ctx context.Context, config *dcl.Config, u *unstructured.Resource) error { + c := dclService.NewClient(config) + r, err := UnstructuredToChannel(u) + if err != nil { + return err + } + return c.DeleteChannel(ctx, r) +} + +func ChannelID(u *unstructured.Resource) (string, error) { + r, err := UnstructuredToChannel(u) + if err != nil { + return "", err + } + return r.ID() +} + +func (r *Channel) STV() unstructured.ServiceTypeVersion { + return unstructured.ServiceTypeVersion{ + "eventarc", + "Channel", + "alpha", + } +} + +func (r *Channel) SetPolicyMember(ctx context.Context, config *dcl.Config, resource *unstructured.Resource, member *unstructured.Resource) (*unstructured.Resource, error) { + return nil, unstructured.ErrNoSuchMethod +} + +func (r *Channel) GetPolicyMember(ctx context.Context, config *dcl.Config, resource *unstructured.Resource, role, member string) (*unstructured.Resource, error) { + return nil, unstructured.ErrNoSuchMethod +} + +func (r *Channel) DeletePolicyMember(ctx context.Context, config *dcl.Config, resource *unstructured.Resource, member *unstructured.Resource) error { + return unstructured.ErrNoSuchMethod +} + +func (r *Channel) SetPolicy(ctx context.Context, config *dcl.Config, resource *unstructured.Resource, policy *unstructured.Resource) (*unstructured.Resource, error) { + return nil, unstructured.ErrNoSuchMethod +} + +func (r *Channel) SetPolicyWithEtag(ctx context.Context, config *dcl.Config, resource *unstructured.Resource, policy *unstructured.Resource) (*unstructured.Resource, error) { + return nil, unstructured.ErrNoSuchMethod +} + +func (r *Channel) GetPolicy(ctx context.Context, config *dcl.Config, resource *unstructured.Resource) (*unstructured.Resource, error) { + return nil, unstructured.ErrNoSuchMethod +} + +func (r *Channel) Get(ctx context.Context, config *dcl.Config, resource *unstructured.Resource) (*unstructured.Resource, error) { + return GetChannel(ctx, config, resource) +} + +func (r *Channel) Apply(ctx context.Context, config *dcl.Config, resource *unstructured.Resource, opts ...dcl.ApplyOption) (*unstructured.Resource, error) { + return ApplyChannel(ctx, config, resource, opts...) +} + +func (r *Channel) HasDiff(ctx context.Context, config *dcl.Config, resource *unstructured.Resource, opts ...dcl.ApplyOption) (bool, error) { + return ChannelHasDiff(ctx, config, resource, opts...) +} + +func (r *Channel) Delete(ctx context.Context, config *dcl.Config, resource *unstructured.Resource) error { + return DeleteChannel(ctx, config, resource) +} + +func (r *Channel) ID(resource *unstructured.Resource) (string, error) { + return ChannelID(resource) +} + +func init() { + unstructured.Register(&Channel{}) +} diff --git a/unstructured/google/eventarc/beta/channel.go b/unstructured/google/eventarc/beta/channel.go new file mode 100755 index 000000000..8c1b47703 --- /dev/null +++ b/unstructured/google/eventarc/beta/channel.go @@ -0,0 +1,302 @@ +// Copyright 2022 Google LLC. All Rights Reserved. +// +// 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 eventarc + +import ( + "context" + "fmt" + "github.com/GoogleCloudPlatform/declarative-resource-client-library/dcl" + dclService "github.com/GoogleCloudPlatform/declarative-resource-client-library/services/google/eventarc/beta" + "github.com/GoogleCloudPlatform/declarative-resource-client-library/unstructured" +) + +type Channel struct{} + +func ChannelToUnstructured(r *dclService.Channel) *unstructured.Resource { + u := &unstructured.Resource{ + STV: unstructured.ServiceTypeVersion{ + Service: "eventarc", + Version: "beta", + Type: "Channel", + }, + Object: make(map[string]interface{}), + } + if r.ActivationToken != nil { + u.Object["activationToken"] = *r.ActivationToken + } + if r.CreateTime != nil { + u.Object["createTime"] = *r.CreateTime + } + if r.CryptoKeyName != nil { + u.Object["cryptoKeyName"] = *r.CryptoKeyName + } + if r.Location != nil { + u.Object["location"] = *r.Location + } + if r.Name != nil { + u.Object["name"] = *r.Name + } + if r.Project != nil { + u.Object["project"] = *r.Project + } + if r.Provider != nil { + u.Object["provider"] = *r.Provider + } + if r.PubsubTopic != nil { + u.Object["pubsubTopic"] = *r.PubsubTopic + } + if r.State != nil { + u.Object["state"] = string(*r.State) + } + if r.Uid != nil { + u.Object["uid"] = *r.Uid + } + if r.UpdateTime != nil { + u.Object["updateTime"] = *r.UpdateTime + } + return u +} + +func UnstructuredToChannel(u *unstructured.Resource) (*dclService.Channel, error) { + r := &dclService.Channel{} + if _, ok := u.Object["activationToken"]; ok { + if s, ok := u.Object["activationToken"].(string); ok { + r.ActivationToken = dcl.String(s) + } else { + return nil, fmt.Errorf("r.ActivationToken: expected string") + } + } + if _, ok := u.Object["createTime"]; ok { + if s, ok := u.Object["createTime"].(string); ok { + r.CreateTime = dcl.String(s) + } else { + return nil, fmt.Errorf("r.CreateTime: expected string") + } + } + if _, ok := u.Object["cryptoKeyName"]; ok { + if s, ok := u.Object["cryptoKeyName"].(string); ok { + r.CryptoKeyName = dcl.String(s) + } else { + return nil, fmt.Errorf("r.CryptoKeyName: expected string") + } + } + if _, ok := u.Object["location"]; ok { + if s, ok := u.Object["location"].(string); ok { + r.Location = dcl.String(s) + } else { + return nil, fmt.Errorf("r.Location: expected string") + } + } + if _, ok := u.Object["name"]; ok { + if s, ok := u.Object["name"].(string); ok { + r.Name = dcl.String(s) + } else { + return nil, fmt.Errorf("r.Name: expected string") + } + } + if _, ok := u.Object["project"]; ok { + if s, ok := u.Object["project"].(string); ok { + r.Project = dcl.String(s) + } else { + return nil, fmt.Errorf("r.Project: expected string") + } + } + if _, ok := u.Object["provider"]; ok { + if s, ok := u.Object["provider"].(string); ok { + r.Provider = dcl.String(s) + } else { + return nil, fmt.Errorf("r.Provider: expected string") + } + } + if _, ok := u.Object["pubsubTopic"]; ok { + if s, ok := u.Object["pubsubTopic"].(string); ok { + r.PubsubTopic = dcl.String(s) + } else { + return nil, fmt.Errorf("r.PubsubTopic: expected string") + } + } + if _, ok := u.Object["state"]; ok { + if s, ok := u.Object["state"].(string); ok { + r.State = dclService.ChannelStateEnumRef(s) + } else { + return nil, fmt.Errorf("r.State: expected string") + } + } + if _, ok := u.Object["uid"]; ok { + if s, ok := u.Object["uid"].(string); ok { + r.Uid = dcl.String(s) + } else { + return nil, fmt.Errorf("r.Uid: expected string") + } + } + if _, ok := u.Object["updateTime"]; ok { + if s, ok := u.Object["updateTime"].(string); ok { + r.UpdateTime = dcl.String(s) + } else { + return nil, fmt.Errorf("r.UpdateTime: expected string") + } + } + return r, nil +} + +func GetChannel(ctx context.Context, config *dcl.Config, u *unstructured.Resource) (*unstructured.Resource, error) { + c := dclService.NewClient(config) + r, err := UnstructuredToChannel(u) + if err != nil { + return nil, err + } + r, err = c.GetChannel(ctx, r) + if err != nil { + return nil, err + } + return ChannelToUnstructured(r), nil +} + +func ListChannel(ctx context.Context, config *dcl.Config, project string, location string) ([]*unstructured.Resource, error) { + c := dclService.NewClient(config) + l, err := c.ListChannel(ctx, project, location) + if err != nil { + return nil, err + } + var resources []*unstructured.Resource + for { + for _, r := range l.Items { + resources = append(resources, ChannelToUnstructured(r)) + } + if !l.HasNext() { + break + } + if err := l.Next(ctx, c); err != nil { + return nil, err + } + } + return resources, nil +} + +func ApplyChannel(ctx context.Context, config *dcl.Config, u *unstructured.Resource, opts ...dcl.ApplyOption) (*unstructured.Resource, error) { + c := dclService.NewClient(config) + r, err := UnstructuredToChannel(u) + if err != nil { + return nil, err + } + if ush := unstructured.FetchStateHint(opts); ush != nil { + sh, err := UnstructuredToChannel(ush) + if err != nil { + return nil, err + } + opts = append(opts, dcl.WithStateHint(sh)) + } + r, err = c.ApplyChannel(ctx, r, opts...) + if err != nil { + return nil, err + } + return ChannelToUnstructured(r), nil +} + +func ChannelHasDiff(ctx context.Context, config *dcl.Config, u *unstructured.Resource, opts ...dcl.ApplyOption) (bool, error) { + c := dclService.NewClient(config) + r, err := UnstructuredToChannel(u) + if err != nil { + return false, err + } + if ush := unstructured.FetchStateHint(opts); ush != nil { + sh, err := UnstructuredToChannel(ush) + if err != nil { + return false, err + } + opts = append(opts, dcl.WithStateHint(sh)) + } + opts = append(opts, dcl.WithLifecycleParam(dcl.BlockDestruction), dcl.WithLifecycleParam(dcl.BlockCreation), dcl.WithLifecycleParam(dcl.BlockModification)) + _, err = c.ApplyChannel(ctx, r, opts...) + if err != nil { + if _, ok := err.(dcl.ApplyInfeasibleError); ok { + return true, nil + } + return false, err + } + return false, nil +} + +func DeleteChannel(ctx context.Context, config *dcl.Config, u *unstructured.Resource) error { + c := dclService.NewClient(config) + r, err := UnstructuredToChannel(u) + if err != nil { + return err + } + return c.DeleteChannel(ctx, r) +} + +func ChannelID(u *unstructured.Resource) (string, error) { + r, err := UnstructuredToChannel(u) + if err != nil { + return "", err + } + return r.ID() +} + +func (r *Channel) STV() unstructured.ServiceTypeVersion { + return unstructured.ServiceTypeVersion{ + "eventarc", + "Channel", + "beta", + } +} + +func (r *Channel) SetPolicyMember(ctx context.Context, config *dcl.Config, resource *unstructured.Resource, member *unstructured.Resource) (*unstructured.Resource, error) { + return nil, unstructured.ErrNoSuchMethod +} + +func (r *Channel) GetPolicyMember(ctx context.Context, config *dcl.Config, resource *unstructured.Resource, role, member string) (*unstructured.Resource, error) { + return nil, unstructured.ErrNoSuchMethod +} + +func (r *Channel) DeletePolicyMember(ctx context.Context, config *dcl.Config, resource *unstructured.Resource, member *unstructured.Resource) error { + return unstructured.ErrNoSuchMethod +} + +func (r *Channel) SetPolicy(ctx context.Context, config *dcl.Config, resource *unstructured.Resource, policy *unstructured.Resource) (*unstructured.Resource, error) { + return nil, unstructured.ErrNoSuchMethod +} + +func (r *Channel) SetPolicyWithEtag(ctx context.Context, config *dcl.Config, resource *unstructured.Resource, policy *unstructured.Resource) (*unstructured.Resource, error) { + return nil, unstructured.ErrNoSuchMethod +} + +func (r *Channel) GetPolicy(ctx context.Context, config *dcl.Config, resource *unstructured.Resource) (*unstructured.Resource, error) { + return nil, unstructured.ErrNoSuchMethod +} + +func (r *Channel) Get(ctx context.Context, config *dcl.Config, resource *unstructured.Resource) (*unstructured.Resource, error) { + return GetChannel(ctx, config, resource) +} + +func (r *Channel) Apply(ctx context.Context, config *dcl.Config, resource *unstructured.Resource, opts ...dcl.ApplyOption) (*unstructured.Resource, error) { + return ApplyChannel(ctx, config, resource, opts...) +} + +func (r *Channel) HasDiff(ctx context.Context, config *dcl.Config, resource *unstructured.Resource, opts ...dcl.ApplyOption) (bool, error) { + return ChannelHasDiff(ctx, config, resource, opts...) +} + +func (r *Channel) Delete(ctx context.Context, config *dcl.Config, resource *unstructured.Resource) error { + return DeleteChannel(ctx, config, resource) +} + +func (r *Channel) ID(resource *unstructured.Resource) (string, error) { + return ChannelID(resource) +} + +func init() { + unstructured.Register(&Channel{}) +} diff --git a/unstructured/google/eventarc/channel.go b/unstructured/google/eventarc/channel.go new file mode 100755 index 000000000..b0a225a04 --- /dev/null +++ b/unstructured/google/eventarc/channel.go @@ -0,0 +1,302 @@ +// Copyright 2022 Google LLC. All Rights Reserved. +// +// 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 eventarc + +import ( + "context" + "fmt" + "github.com/GoogleCloudPlatform/declarative-resource-client-library/dcl" + dclService "github.com/GoogleCloudPlatform/declarative-resource-client-library/services/google/eventarc" + "github.com/GoogleCloudPlatform/declarative-resource-client-library/unstructured" +) + +type Channel struct{} + +func ChannelToUnstructured(r *dclService.Channel) *unstructured.Resource { + u := &unstructured.Resource{ + STV: unstructured.ServiceTypeVersion{ + Service: "eventarc", + Version: "ga", + Type: "Channel", + }, + Object: make(map[string]interface{}), + } + if r.ActivationToken != nil { + u.Object["activationToken"] = *r.ActivationToken + } + if r.CreateTime != nil { + u.Object["createTime"] = *r.CreateTime + } + if r.CryptoKeyName != nil { + u.Object["cryptoKeyName"] = *r.CryptoKeyName + } + if r.Location != nil { + u.Object["location"] = *r.Location + } + if r.Name != nil { + u.Object["name"] = *r.Name + } + if r.Project != nil { + u.Object["project"] = *r.Project + } + if r.Provider != nil { + u.Object["provider"] = *r.Provider + } + if r.PubsubTopic != nil { + u.Object["pubsubTopic"] = *r.PubsubTopic + } + if r.State != nil { + u.Object["state"] = string(*r.State) + } + if r.Uid != nil { + u.Object["uid"] = *r.Uid + } + if r.UpdateTime != nil { + u.Object["updateTime"] = *r.UpdateTime + } + return u +} + +func UnstructuredToChannel(u *unstructured.Resource) (*dclService.Channel, error) { + r := &dclService.Channel{} + if _, ok := u.Object["activationToken"]; ok { + if s, ok := u.Object["activationToken"].(string); ok { + r.ActivationToken = dcl.String(s) + } else { + return nil, fmt.Errorf("r.ActivationToken: expected string") + } + } + if _, ok := u.Object["createTime"]; ok { + if s, ok := u.Object["createTime"].(string); ok { + r.CreateTime = dcl.String(s) + } else { + return nil, fmt.Errorf("r.CreateTime: expected string") + } + } + if _, ok := u.Object["cryptoKeyName"]; ok { + if s, ok := u.Object["cryptoKeyName"].(string); ok { + r.CryptoKeyName = dcl.String(s) + } else { + return nil, fmt.Errorf("r.CryptoKeyName: expected string") + } + } + if _, ok := u.Object["location"]; ok { + if s, ok := u.Object["location"].(string); ok { + r.Location = dcl.String(s) + } else { + return nil, fmt.Errorf("r.Location: expected string") + } + } + if _, ok := u.Object["name"]; ok { + if s, ok := u.Object["name"].(string); ok { + r.Name = dcl.String(s) + } else { + return nil, fmt.Errorf("r.Name: expected string") + } + } + if _, ok := u.Object["project"]; ok { + if s, ok := u.Object["project"].(string); ok { + r.Project = dcl.String(s) + } else { + return nil, fmt.Errorf("r.Project: expected string") + } + } + if _, ok := u.Object["provider"]; ok { + if s, ok := u.Object["provider"].(string); ok { + r.Provider = dcl.String(s) + } else { + return nil, fmt.Errorf("r.Provider: expected string") + } + } + if _, ok := u.Object["pubsubTopic"]; ok { + if s, ok := u.Object["pubsubTopic"].(string); ok { + r.PubsubTopic = dcl.String(s) + } else { + return nil, fmt.Errorf("r.PubsubTopic: expected string") + } + } + if _, ok := u.Object["state"]; ok { + if s, ok := u.Object["state"].(string); ok { + r.State = dclService.ChannelStateEnumRef(s) + } else { + return nil, fmt.Errorf("r.State: expected string") + } + } + if _, ok := u.Object["uid"]; ok { + if s, ok := u.Object["uid"].(string); ok { + r.Uid = dcl.String(s) + } else { + return nil, fmt.Errorf("r.Uid: expected string") + } + } + if _, ok := u.Object["updateTime"]; ok { + if s, ok := u.Object["updateTime"].(string); ok { + r.UpdateTime = dcl.String(s) + } else { + return nil, fmt.Errorf("r.UpdateTime: expected string") + } + } + return r, nil +} + +func GetChannel(ctx context.Context, config *dcl.Config, u *unstructured.Resource) (*unstructured.Resource, error) { + c := dclService.NewClient(config) + r, err := UnstructuredToChannel(u) + if err != nil { + return nil, err + } + r, err = c.GetChannel(ctx, r) + if err != nil { + return nil, err + } + return ChannelToUnstructured(r), nil +} + +func ListChannel(ctx context.Context, config *dcl.Config, project string, location string) ([]*unstructured.Resource, error) { + c := dclService.NewClient(config) + l, err := c.ListChannel(ctx, project, location) + if err != nil { + return nil, err + } + var resources []*unstructured.Resource + for { + for _, r := range l.Items { + resources = append(resources, ChannelToUnstructured(r)) + } + if !l.HasNext() { + break + } + if err := l.Next(ctx, c); err != nil { + return nil, err + } + } + return resources, nil +} + +func ApplyChannel(ctx context.Context, config *dcl.Config, u *unstructured.Resource, opts ...dcl.ApplyOption) (*unstructured.Resource, error) { + c := dclService.NewClient(config) + r, err := UnstructuredToChannel(u) + if err != nil { + return nil, err + } + if ush := unstructured.FetchStateHint(opts); ush != nil { + sh, err := UnstructuredToChannel(ush) + if err != nil { + return nil, err + } + opts = append(opts, dcl.WithStateHint(sh)) + } + r, err = c.ApplyChannel(ctx, r, opts...) + if err != nil { + return nil, err + } + return ChannelToUnstructured(r), nil +} + +func ChannelHasDiff(ctx context.Context, config *dcl.Config, u *unstructured.Resource, opts ...dcl.ApplyOption) (bool, error) { + c := dclService.NewClient(config) + r, err := UnstructuredToChannel(u) + if err != nil { + return false, err + } + if ush := unstructured.FetchStateHint(opts); ush != nil { + sh, err := UnstructuredToChannel(ush) + if err != nil { + return false, err + } + opts = append(opts, dcl.WithStateHint(sh)) + } + opts = append(opts, dcl.WithLifecycleParam(dcl.BlockDestruction), dcl.WithLifecycleParam(dcl.BlockCreation), dcl.WithLifecycleParam(dcl.BlockModification)) + _, err = c.ApplyChannel(ctx, r, opts...) + if err != nil { + if _, ok := err.(dcl.ApplyInfeasibleError); ok { + return true, nil + } + return false, err + } + return false, nil +} + +func DeleteChannel(ctx context.Context, config *dcl.Config, u *unstructured.Resource) error { + c := dclService.NewClient(config) + r, err := UnstructuredToChannel(u) + if err != nil { + return err + } + return c.DeleteChannel(ctx, r) +} + +func ChannelID(u *unstructured.Resource) (string, error) { + r, err := UnstructuredToChannel(u) + if err != nil { + return "", err + } + return r.ID() +} + +func (r *Channel) STV() unstructured.ServiceTypeVersion { + return unstructured.ServiceTypeVersion{ + "eventarc", + "Channel", + "ga", + } +} + +func (r *Channel) SetPolicyMember(ctx context.Context, config *dcl.Config, resource *unstructured.Resource, member *unstructured.Resource) (*unstructured.Resource, error) { + return nil, unstructured.ErrNoSuchMethod +} + +func (r *Channel) GetPolicyMember(ctx context.Context, config *dcl.Config, resource *unstructured.Resource, role, member string) (*unstructured.Resource, error) { + return nil, unstructured.ErrNoSuchMethod +} + +func (r *Channel) DeletePolicyMember(ctx context.Context, config *dcl.Config, resource *unstructured.Resource, member *unstructured.Resource) error { + return unstructured.ErrNoSuchMethod +} + +func (r *Channel) SetPolicy(ctx context.Context, config *dcl.Config, resource *unstructured.Resource, policy *unstructured.Resource) (*unstructured.Resource, error) { + return nil, unstructured.ErrNoSuchMethod +} + +func (r *Channel) SetPolicyWithEtag(ctx context.Context, config *dcl.Config, resource *unstructured.Resource, policy *unstructured.Resource) (*unstructured.Resource, error) { + return nil, unstructured.ErrNoSuchMethod +} + +func (r *Channel) GetPolicy(ctx context.Context, config *dcl.Config, resource *unstructured.Resource) (*unstructured.Resource, error) { + return nil, unstructured.ErrNoSuchMethod +} + +func (r *Channel) Get(ctx context.Context, config *dcl.Config, resource *unstructured.Resource) (*unstructured.Resource, error) { + return GetChannel(ctx, config, resource) +} + +func (r *Channel) Apply(ctx context.Context, config *dcl.Config, resource *unstructured.Resource, opts ...dcl.ApplyOption) (*unstructured.Resource, error) { + return ApplyChannel(ctx, config, resource, opts...) +} + +func (r *Channel) HasDiff(ctx context.Context, config *dcl.Config, resource *unstructured.Resource, opts ...dcl.ApplyOption) (bool, error) { + return ChannelHasDiff(ctx, config, resource, opts...) +} + +func (r *Channel) Delete(ctx context.Context, config *dcl.Config, resource *unstructured.Resource) error { + return DeleteChannel(ctx, config, resource) +} + +func (r *Channel) ID(resource *unstructured.Resource) (string, error) { + return ChannelID(resource) +} + +func init() { + unstructured.Register(&Channel{}) +}